libyui-gtk  2.44.9
YGInputField.cc
1 /********************************************************************
2  * YaST2-GTK - http://en.opensuse.org/YaST2-GTK *
3  ********************************************************************/
4 
5 #define YUILogComponent "gtk"
6 #include <yui/Libyui_config.h>
7 #include "YGUI.h"
8 #include "YGWidget.h"
9 #include "YGUtils.h"
10 #include "ygtkfieldentry.h"
11 
12 #include <YInputField.h>
13 #include <boost/date_time/posix_time/posix_time.hpp>
14 #include <iostream>
15 #include <sstream>
16 
17 using namespace boost::gregorian;
18 
19 class YGInputField : public YInputField, public YGLabeledWidget
20 {
21 public:
22  YGInputField (YWidget *parent, const std::string &label, bool passwordMode)
23  : YInputField (NULL, label, passwordMode),
24  YGLabeledWidget (this, parent, label, YD_HORIZ,
25  YGTK_TYPE_FIELD_ENTRY, NULL)
26  {
27  gtk_widget_set_size_request (getWidget(), 0, -1); // let min size, set width
28  YGtkFieldEntry *field = YGTK_FIELD_ENTRY (getWidget());
29  ygtk_field_entry_add_field (field, 0);
30 
31  GtkEntry *entry = ygtk_field_entry_get_field_widget (field, 0);
32  gtk_entry_set_activates_default (entry, TRUE);
33  gtk_entry_set_visibility (entry, !passwordMode);
34 
35  connect (getWidget(), "field-entry-changed", G_CALLBACK (value_changed_cb), this);
36  }
37 
38  // YInputField
39  virtual std::string value()
40  {
41  YGtkFieldEntry *field = YGTK_FIELD_ENTRY (getWidget());
42  return ygtk_field_entry_get_field_text (field, 0);
43  }
44 
45  virtual void setValue (const std::string &text)
46  {
47  BlockEvents block (this);
48  YGtkFieldEntry *field = YGTK_FIELD_ENTRY (getWidget());
49  ygtk_field_entry_set_field_text (field, 0, text.c_str());
50  }
51 
52  void updateProps()
53  {
54  YGtkFieldEntry *field = YGTK_FIELD_ENTRY (getWidget());
55  ygtk_field_entry_setup_field (field, 0, inputMaxLength(), validChars().c_str());
56  }
57 
58  virtual void setInputMaxLength (int len)
59  {
60  YInputField::setInputMaxLength (len);
61  updateProps();
62  }
63 
64  virtual void setValidChars (const std::string &validChars)
65  {
66  YInputField::setValidChars (validChars);
67  updateProps();
68  }
69 
70  // callbacks
71  static void value_changed_cb (YGtkFieldEntry *entry, gint field_nb, YGInputField *pThis)
72  { pThis->emitEvent (YEvent::ValueChanged); }
73 
74  // YGWidget
75  virtual bool doSetKeyboardFocus()
76  {
77  YGtkFieldEntry *field = YGTK_FIELD_ENTRY (getWidget());
78  return ygtk_field_entry_set_focus (field);
79  }
80 
81  virtual unsigned int getMinSize (YUIDimension dim)
82  { return dim == YD_HORIZ ? (shrinkable() ? 30 : 200) : 0; }
83 
84  YGLABEL_WIDGET_IMPL (YInputField)
85 };
86 
87 YInputField *YGWidgetFactory::createInputField (YWidget *parent, const std::string &label,
88  bool passwordMode)
89 {
90  return new YGInputField (parent, label, passwordMode);
91 }
92 
93 #include "YTimeField.h"
94 
95 class YGTimeField : public YTimeField, public YGLabeledWidget
96 {
97  std::string old_time;
98 public:
99  YGTimeField (YWidget *parent, const std::string &label)
100  : YTimeField (NULL, label),
101  YGLabeledWidget (this, parent, label, YD_HORIZ,
102  YGTK_TYPE_FIELD_ENTRY, NULL)
103  {
104  // Same default as Qt
105  old_time = "00:00:00";
106  YGtkFieldEntry *field = YGTK_FIELD_ENTRY (getWidget());
107  ygtk_field_entry_add_field (field, ':');
108  ygtk_field_entry_add_field (field, ':');
109  ygtk_field_entry_add_field (field, ':');
110  ygtk_field_entry_setup_field (field, 0, 2, "0123456789");
111  ygtk_field_entry_setup_field (field, 1, 2, "0123456789");
112  ygtk_field_entry_setup_field (field, 2, 2, "0123456789");
113 
114  setValue ( old_time );
115 
116  connect (getWidget(), "field-entry-changed", G_CALLBACK (value_changed_cb), this);
117  }
118 
119  bool validTime(const std::string& input_time)
120  {
121  tm tm1;
122  std::stringstream ss;
123  ss << input_time;
124  char c;
125 
126  if (!(ss >> tm1.tm_hour))
127  return false;
128  ss >> c;
129 
130  if (!(ss >> tm1.tm_min))
131  return false;
132  ss >> c;
133 
134  if (!(ss >> tm1.tm_sec))
135  return false;
136 
137  return (tm1.tm_hour<=23 && tm1.tm_min <= 59 && tm1.tm_sec <= 59);
138  }
139 
140  // YTimeField
141  virtual void setValue (const std::string &time)
142  {
143  BlockEvents block (this);
144  if (time.empty()) return;
145  if (!validTime(time)) return;
146 
147  char hours[3], mins[3], secs[3];
148  sscanf (time.c_str(), "%2s:%2s:%2s", hours, mins, secs);
149 
150  YGtkFieldEntry *entry = YGTK_FIELD_ENTRY (getWidget());
151  ygtk_field_entry_set_field_text (entry, 0, hours);
152  ygtk_field_entry_set_field_text (entry, 1, mins);
153  ygtk_field_entry_set_field_text (entry, 2, secs);
154 
155  old_time = time;
156  }
157 
158  virtual std::string value()
159  {
160  const gchar *hours, *mins, *secs;
161  YGtkFieldEntry *entry = YGTK_FIELD_ENTRY (getWidget());
162  if (!gtk_entry_get_text_length (ygtk_field_entry_get_field_widget (entry, 0)) ||
163  !gtk_entry_get_text_length (ygtk_field_entry_get_field_widget (entry, 1)) ||
164  !gtk_entry_get_text_length (ygtk_field_entry_get_field_widget (entry, 2)))
165  return old_time;
166 
167  hours = ygtk_field_entry_get_field_text (entry, 0);
168  mins = ygtk_field_entry_get_field_text (entry, 1);
169  secs = ygtk_field_entry_get_field_text (entry, 2);
170 
171  gchar *time = g_strdup_printf ("%02d:%02d:%02d", atoi (hours), atoi (mins), atoi (secs));
172  std::string str (time);
173  g_free (time);
174  return str;
175  }
176 
177  // callbacks
178  static void value_changed_cb (YGtkFieldEntry *entry, gint field_nb,
179  YGTimeField *pThis)
180  {
181  if (!gtk_entry_get_text_length (ygtk_field_entry_get_field_widget (entry, 0)) ||
182  !gtk_entry_get_text_length (ygtk_field_entry_get_field_widget (entry, 1)) ||
183  !gtk_entry_get_text_length (ygtk_field_entry_get_field_widget (entry, 2)))
184  return;
185 
186  if (pThis->validTime(pThis->value()))
187  {
188  pThis->old_time = pThis->value();
189  pThis->emitEvent (YEvent::ValueChanged);
190  }
191  else
192  {
193  pThis->setValue(pThis->old_time);
194  }
195  }
196 
197  YGLABEL_WIDGET_IMPL (YTimeField)
198 };
199 
200 YTimeField *YGOptionalWidgetFactory::createTimeField (YWidget *parent, const std::string &label)
201 { return new YGTimeField (parent, label); }
202 
203 #include "YDateField.h"
204 #include "ygtkmenubutton.h"
205 
206 class YGDateField : public YDateField, public YGLabeledWidget
207 {
208 GtkWidget *m_calendar, *m_popup_calendar;
209 std::string old_date;
210 
211 public:
212  YGDateField (YWidget *parent, const std::string &label)
213  : YDateField (NULL, label),
214  YGLabeledWidget (this, parent, label, YD_HORIZ, YGTK_TYPE_FIELD_ENTRY, NULL)
215  {
216  // Same value as QT default
217  old_date = "2000-01-01";
218  ygtk_field_entry_add_field (getField(), '-');
219  ygtk_field_entry_add_field (getField(), '-');
220  ygtk_field_entry_add_field (getField(), '-');
221  ygtk_field_entry_setup_field (getField(), 0, 4, "0123456789");
222  ygtk_field_entry_setup_field (getField(), 1, 2, "0123456789");
223  ygtk_field_entry_setup_field (getField(), 2, 2, "0123456789");
224 
225  m_calendar = gtk_calendar_new();
226  gtk_widget_show (m_calendar);
227  GtkWidget *popup = ygtk_popup_window_new (m_calendar);
228 
229  GtkWidget *menu_button = ygtk_menu_button_new_with_label ("");
230  ygtk_menu_button_set_popup (YGTK_MENU_BUTTON (menu_button), popup);
231  gtk_widget_show (menu_button);
232  gtk_box_pack_start (GTK_BOX (getWidget()), menu_button, FALSE, TRUE, 6);
233 
234  setValue(old_date);
235 
236  connect (getWidget(), "field-entry-changed", G_CALLBACK (value_changed_cb), this);
237  connect (m_calendar, "day-selected", G_CALLBACK (calendar_changed_cb), this);
238  g_signal_connect (G_OBJECT (m_calendar), "day-selected-double-click",
239  G_CALLBACK (double_click_cb), popup);
240  }
241 
242  inline GtkCalendar *getCalendar()
243  { return GTK_CALENDAR (m_calendar); }
244  inline YGtkFieldEntry *getField()
245  { return YGTK_FIELD_ENTRY (getWidget()); }
246 
247  bool validDate(const std::string& input_date)
248  {
249  std::wstringstream ss;
250  wdate_input_facet * fac = new wdate_input_facet(L"%Y-%m-%d");
251  ss.imbue(std::locale(std::locale::classic(), fac));
252 
253  date d;
254  ss << input_date.c_str();
255  ss >> d;
256  return d != date();
257  }
258 
259  // YDateField
260  virtual void setValue (const std::string &date)
261  {
262  BlockEvents block (this);
263  if (date.empty()) return;
264  if (!validDate(date)) return;
265 
266  char year[5], month[3], day[3];
267  sscanf (date.c_str(), "%4s-%2s-%2s", year, month, day);
268 
269  gtk_calendar_select_month (getCalendar(), atoi (month)-1, atoi (year));
270  gtk_calendar_select_day (getCalendar(), atoi (day));
271 
272  ygtk_field_entry_set_field_text (getField(), 0, year);
273  ygtk_field_entry_set_field_text (getField(), 1, month);
274  ygtk_field_entry_set_field_text (getField(), 2, day);
275  old_date = date;
276  }
277 
278  virtual std::string value()
279  {
280  if (gtk_entry_get_text_length (ygtk_field_entry_get_field_widget (getField(), 0)) < 4 ||
281  !gtk_entry_get_text_length (ygtk_field_entry_get_field_widget (getField(), 1)) ||
282  !gtk_entry_get_text_length (ygtk_field_entry_get_field_widget (getField(), 2)))
283  return old_date;
284 
285  const gchar *year, *month, *day;
286  year = ygtk_field_entry_get_field_text (getField(), 0);
287  month = ygtk_field_entry_get_field_text (getField(), 1);
288  day = ygtk_field_entry_get_field_text (getField(), 2);
289 
290  gchar *time = g_strdup_printf ("%04d-%02d-%02d", atoi (year),
291  atoi (month), atoi (day));
292  std::string str (time);
293  g_free (time);
294  return str;
295  }
296 
297  // callbacks
298  static void value_changed_cb (YGtkFieldEntry *entry, gint field_nb,
299  YGDateField *pThis)
300  {
301  if (gtk_entry_get_text_length (ygtk_field_entry_get_field_widget (entry, 0)) < 4 ||
302  !gtk_entry_get_text_length (ygtk_field_entry_get_field_widget (entry, 1)) ||
303  !gtk_entry_get_text_length (ygtk_field_entry_get_field_widget (entry, 2)))
304  return;
305 
306  std::string new_date = pThis->value();
307  bool changed = false;
308 
309  if (pThis->validDate(new_date))
310  {
311  changed = true;
312  pThis->old_date = new_date;
313  }
314  else
315  {
316  pThis->setValue(pThis->old_date);
317  }
318 
319  if (changed)
320  {
321  int year, month, day;
322  year = atoi (ygtk_field_entry_get_field_text (pThis->getField(), 0));
323  month = atoi (ygtk_field_entry_get_field_text (pThis->getField(), 1));
324  day = atoi (ygtk_field_entry_get_field_text (pThis->getField(), 2));
325 
326  g_signal_handlers_block_by_func (pThis->getCalendar(),
327  (gpointer) calendar_changed_cb, pThis);
328  gtk_calendar_select_month (pThis->getCalendar(), month-1, year);
329  gtk_calendar_select_day (pThis->getCalendar(), day);
330  g_signal_handlers_unblock_by_func (pThis->getCalendar(),
331  (gpointer) calendar_changed_cb, pThis);
332 
333  pThis->emitEvent (YEvent::ValueChanged);
334  }
335  }
336 
337  static void calendar_changed_cb (GtkCalendar *calendar, YGDateField *pThis)
338  {
339  guint year, month, day;
340  gtk_calendar_get_date (calendar, &year, &month, &day);
341  month += 1; // GTK calendar months go from 0 to 11
342 
343  gchar *year_str, *month_str, *day_str;
344  year_str = g_strdup_printf ("%d", year);
345  month_str = g_strdup_printf ("%d", month);
346  day_str = g_strdup_printf ("%d", day);
347 
348  g_signal_handlers_block_by_func (pThis->getField(),
349  (gpointer) value_changed_cb, pThis);
350 
351  YGtkFieldEntry *entry = pThis->getField();
352  ygtk_field_entry_set_field_text (entry, 0, year_str);
353  ygtk_field_entry_set_field_text (entry, 1, month_str);
354  ygtk_field_entry_set_field_text (entry, 2, day_str);
355 
356  pThis->old_date = pThis->value();
357  g_signal_handlers_unblock_by_func (pThis->getField(),
358  (gpointer) value_changed_cb, pThis);
359 
360  g_free (year_str);
361  g_free (month_str);
362  g_free (day_str);
363 
364  pThis->emitEvent (YEvent::ValueChanged);
365  }
366 
367  static void double_click_cb (GtkCalendar *calendar, YGtkPopupWindow *popup)
368  {
369  // close popup
370  gtk_widget_hide (GTK_WIDGET (popup));
371  }
372 
373  YGLABEL_WIDGET_IMPL (YDateField)
374 };
375 
376 YDateField *YGOptionalWidgetFactory::createDateField (YWidget *parent, const std::string &label)
377 { return new YGDateField (parent, label); }
378 
379 #include "YTimezoneSelector.h"
380 #include "ygtktimezonepicker.h"
381 
382 class YGTimezoneSelector : public YTimezoneSelector, public YGWidget
383 {
384 public:
385  YGTimezoneSelector (YWidget *parent, const std::string &pixmap,
386  const std::map <std::string, std::string> &timezones)
387  : YTimezoneSelector (NULL, pixmap, timezones),
388  YGWidget (this, parent, YGTK_TYPE_TIME_ZONE_PICKER, NULL)
389  {
390  setStretchable (YD_HORIZ, true);
391  setStretchable (YD_VERT, true);
392  ygtk_time_zone_picker_set_map (YGTK_TIME_ZONE_PICKER (getWidget()),
393  pixmap.c_str(), convert_code_to_name, (gpointer) &timezones);
394 
395  connect (getWidget(), "zone-clicked", G_CALLBACK (zone_clicked_cb), this);
396  }
397 
398  // YTimezoneSelector
399  virtual std::string currentZone() const
400  {
401  YGTimezoneSelector *pThis = const_cast <YGTimezoneSelector *> (this);
402  const gchar *zone = ygtk_time_zone_picker_get_current_zone (
403  YGTK_TIME_ZONE_PICKER (pThis->getWidget()));
404  if (zone)
405  return zone;
406  return std::string();
407  }
408 
409  virtual void setCurrentZone (const std::string &zone, bool zoom)
410  {
411  BlockEvents block (this);
412  ygtk_time_zone_picker_set_current_zone (YGTK_TIME_ZONE_PICKER (getWidget()),
413  zone.c_str(), zoom);
414  }
415 
416  // YGtkTimeZonePicker
417  static const gchar *convert_code_to_name (const gchar *code, gpointer pData)
418  {
419  const std::map <std::string, std::string> *timezones =
420  (std::map <std::string, std::string> *) pData;
421  std::map <std::string, std::string>::const_iterator name =
422  timezones->find (code);
423  if (name == timezones->end())
424  return NULL;
425  return name->second.c_str();
426  }
427 
428  // callbacks
429  static void zone_clicked_cb (YGtkTimeZonePicker *picker, const gchar *zone,
430  YGTimezoneSelector *pThis)
431  { pThis->emitEvent (YEvent::ValueChanged); }
432 
433  YGWIDGET_IMPL_COMMON (YTimezoneSelector)
434 };
435 
436 YTimezoneSelector *YGOptionalWidgetFactory::createTimezoneSelector (YWidget *parent,
437  const std::string &pixmap, const std::map <std::string, std::string> &timezones)
438 { return new YGTimezoneSelector (parent, pixmap, timezones); }
439