libyui  3.10.0
YPropertyEditor.cc
1 /*
2  Copyright (C) 2016 SUSE LLC
3 
4  This library is free software; you can redistribute it and/or modify
5  it under the terms of the GNU Lesser General Public License as
6  published by the Free Software Foundation; either version 2.1 of the
7  License, or (at your option) version 3.0 of the License. This library
8  is distributed in the hope that it will be useful, but WITHOUT ANY
9  WARRANTY; without even the implied warranty of MERCHANTABILITY or
10  FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
11  License for more details. You should have received a copy of the GNU
12  Lesser General Public License along with this library; if not, write
13  to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
14  Floor, Boston, MA 02110-1301 USA
15 */
16 
17 #include <YPropertyEditor.h>
18 
19 #include <YUI.h>
20 #include <YWidgetFactory.h>
21 #include <YDialog.h>
22 #include <YLayoutBox.h>
23 #include <YAlignment.h>
24 #include <YButtonBox.h>
25 #include <YPushButton.h>
26 #include <YEvent.h>
27 #include <YPopupInternal.h>
28 #include <YComboBox.h>
29 #include <YInputField.h>
30 #include <YIntField.h>
31 
32 #include <limits>
33 
34 #define YUILogComponent "ui-property-editor"
35 #include "YUILog.h"
36 
37 using std::string;
38 
39 
41 {
42 public:
43 
44  YPropertyEditorPriv(YWidget * widget) : _widget(widget),
45  popup(nullptr), combo(nullptr), intfield(nullptr),
46  input(nullptr), okButton(nullptr), cancelButton(nullptr)
47  {}
48 
49  bool edit( const string &property );
50 
51 private:
52 
53  /**
54  * show the dialog on the screen
55  * @param property Name of the property to edit
56  */
57  void show( const string &property );
58 
59  /**
60  * Run the main event loop
61  * @param property Name of the property to edit
62  * @return true if the value has been changed, false otherwise
63  */
64  bool run( const string &property );
65 
66  /**
67  * Close the dialog window
68  */
69  void close();
70 
71  /**
72  * Refresh the dialog conatining the widget
73  */
74  void refreshDialog();
75 
76  YWidget * _widget;
77 
78  /**
79  * Is the property read-only?
80  * @param property Name of the property
81  * @return true if it is read-only, false if it can be changed
82  */
83  bool isReadOnly( const string &property );
84 
85  // UI widgets
86  // the main popup
87  YDialog *popup;
88 
89  // input widgets
90  YComboBox *combo;
91  YIntField *intfield;
92  YInputField *input;
93 
94  // buttons
95  YPushButton *okButton;
96  YPushButton *cancelButton;
97 
98  /**
99  * Is the property editable? Editable property is not read-only and
100  * it is String, Integer or Boolean type.
101  * @param property Name of the property
102  * @return true if the property can be changed
103  */
104  bool editable(const string &property);
105 };
106 
107 
108 /**
109  * Helper method - refresh the dialog containing the widget
110  * @param widget [description]
111  */
112 void YPropertyEditorPriv::refreshDialog()
113 {
114  auto dialog = _widget->findDialog();
115  if (dialog) dialog->recalcLayout();
116 }
117 
118 
119 bool YPropertyEditorPriv::edit(const string &property)
120 {
121  if (!_widget || !editable(property)) return false;
122 
123  yuiMilestone() << "editing property \"" << property << "\" (type: " <<
124  _widget->getProperty(property).typeAsStr() << ")";
125 
126  show(property);
127  bool changed = run(property);
128  close();
129 
130  return changed;
131 }
132 
133 
134 bool YPropertyEditorPriv::isReadOnly(const string &property)
135 {
136  // is the property read-only?
137  YPropertySet propSet = _widget->propertySet();
138  for ( YPropertySet::const_iterator it = propSet.propertiesBegin();
139  it != propSet.propertiesEnd();
140  ++it )
141  {
142  YProperty prop = *it;
143 
144  if (prop.name() == property)
145  {
146  return prop.isReadOnly();
147  }
148  }
149 
150  // we cannot edit an unknown property, throw an exception
151  YUI_THROW( YUIException( "Unknown property: " + property) );
152 
153  // FIXME: never reached, just make the compiler happy (can it be improved?)
154  return false;
155 }
156 
157 
158 void YPropertyEditorPriv::show(const string &property)
159 {
160  YPropertyValue prop_value = _widget->getProperty(property);
161  YPropertyType type = prop_value.type();
162 
163  auto f = YUI::widgetFactory();
164 
165  popup = f->createPopupDialog();
166  auto vbox = f->createVBox(popup);
167 
168  if (type == YBoolProperty)
169  {
170  combo = f->createComboBox(vbox, property);
171  combo->setNotify(true);
172 
173  YItemCollection items;
174  items.push_back(new YItem("true"));
175  items.push_back(new YItem("false"));
176  combo->addItems(items);
177  combo->setValue(prop_value.boolVal() ? "true" : "false");
178  }
179  else if (type == YIntegerProperty)
180  {
181  intfield = f->createIntField(vbox, property,
182  // we do not know anything about that property so use the
183  // max int and min int values here
184  std::numeric_limits<int>::min(),
185  std::numeric_limits<int>::max(),
186  prop_value.integerVal());
187  intfield->setNotify(true);
188  }
189  else if (type == YStringProperty)
190  {
191  input = f->createInputField(vbox, property);
192  input->setNotify(true);
193  input->setValue(prop_value.stringVal());
194  }
195 
196  auto bbox = f->createButtonBox(vbox);
197  okButton = f->createPushButton(bbox, "OK");
198  okButton->setRole(YOKButton);
199  okButton->setDefaultButton();
200  cancelButton = f->createPushButton(bbox, "Cancel");
201  cancelButton->setRole(YCancelButton);
202 }
203 
204 
205 void YPropertyEditorPriv::close()
206 {
207  popup->destroy();
208 
209  // nullify the widget pointers, just to be sure...
210  popup = NULL;
211  okButton = NULL;
212  cancelButton = NULL;
213  combo = NULL;
214  intfield = NULL;
215  input = NULL;
216 }
217 
218 
219 bool YPropertyEditorPriv::run(const string &property)
220 {
221  // backup the original property value so it can be restored after
222  // clicking the [Cancel] button later
223  YPropertyValue orig = _widget->getProperty(property);;
224 
225  while (true)
226  {
227  YEvent * event = popup->waitForEvent();
228  if (event)
229  {
230  if (event->widget() == cancelButton || event->eventType() == YEvent::CancelEvent)
231  {
232  // restore the original value
233  if (_widget->getProperty(property) != orig)
234  {
235  _widget->setProperty(property, orig);
236  refreshDialog();
237  }
238 
239  // not modified
240  return false;
241  }
242  else if (event->widget() == okButton)
243  {
244  return _widget->getProperty(property) != orig;
245  }
246  else if (event->widget() == combo)
247  {
248  string value = combo->value();
249  yuiMilestone() << "Value changed to " << value;
250  _widget->setProperty(property, YPropertyValue(value == "true"));
251  refreshDialog();
252  }
253  else if (event->widget() == input)
254  {
255  string value = input->value();
256  yuiMilestone() << "Value changed to " << value;
257 
258  _widget->setProperty(property, YPropertyValue(value));
259  refreshDialog();
260  }
261  else if (event->widget() == intfield)
262  {
263  int value = intfield->value();
264  yuiMilestone() << "Value changed to " << value;
265 
266  _widget->setProperty(property, YPropertyValue(value));
267  refreshDialog();
268  }
269  }
270  }
271 }
272 
273 bool YPropertyEditorPriv::editable(const string &property)
274 {
275  YPropertyValue prop_value = _widget->getProperty(property);
276 
277  // is the property read-only?
278  if (isReadOnly(property))
279  {
280  YPopupInternal::message("Property \"" + property + "\" is read only!");
281  return false;
282  }
283 
284  YPropertyType type = prop_value.type();
285  // edit special properties cannot be edited
286  if (type != YBoolProperty && type != YStringProperty && type != YIntegerProperty)
287  {
288  return false;
289  }
290 
291  return true;
292 }
293 
294 
295 bool YPropertyEditor::edit(const string &property)
296 {
297  return priv->edit(property);
298 }
299 
300 
302  : priv(new YPropertyEditorPriv(widget))
303 {
304 }
305 
306 
307 YPropertyEditor::~YPropertyEditor()
308 {
309 }
std::vector< YItem * > YItemCollection
Collection of pointers to YItem.
Definition: YItem.h:38
ComboBox (or "drop down box", "drop down selection"); may be editable.
Definition: YComboBox.h:54
void setValue(const std::string &newText)
Set the value of this ComboBox by string: Try to find a list item with that label and select it.
Definition: YComboBox.cc:102
std::string value()
Return the value of this ComboBox:
Definition: YComboBox.cc:96
A window in the desktop environment.
Definition: YDialog.h:48
bool destroy(bool doThrow=true)
Close and delete this dialog (and all its children) if it is the topmost dialog.
Definition: YDialog.cc:238
YEvent * waitForEvent(int timeout_millisec=0)
Wait for a user event.
Definition: YDialog.cc:387
void recalcLayout()
Recalculate the layout of the dialog and of all its children after children have been added or remove...
Definition: YDialog.cc:356
Abstract base class for events to be returned upon UI::UserInput() and related functions.
Definition: YEvent.h:44
InputField: General purpose one line input field for entering text and other data.
Definition: YInputField.h:47
virtual void setValue(const std::string &text)=0
Set the current value (the text entered by the user or set from the outside) of this input field.
virtual std::string value()=0
Get the current value (the text entered by the user or set from the outside) of this input field.
IntField: Input field for integer values.
Definition: YIntField.h:39
virtual int value()=0
Get the current value (the number entered by the user or set from the outside) of this IntField.
Simple item class for SelectionBox, ComboBox, MultiSelectionBox etc.
Definition: YItem.h:50
static void message(const std::string &label)
Display a simple popup dialog with OK button.
YPropertyEditor(YWidget *widget)
Constructor.
bool edit(const std::string &property)
Display a popup for editing a widget property.
A set of properties to check names and types against.
Definition: YProperty.h:198
const_iterator propertiesBegin() const
Returns an iterator that points to the first property in this set.
Definition: YProperty.cc:165
const_iterator propertiesEnd() const
Returns an iterator that points after the last property in this set.
Definition: YProperty.cc:171
Transport class for the value of simple properties.
Definition: YProperty.h:105
std::string typeAsStr() const
Returns the type of this property value as string.
Definition: YProperty.h:174
std::string stringVal() const
Methods to get the value of this property.
Definition: YProperty.h:180
YPropertyType type() const
Returns the type of this property value.
Definition: YProperty.h:169
Class for widget properties.
Definition: YProperty.h:52
std::string name() const
Returns the name of this property.
Definition: YProperty.h:67
bool isReadOnly() const
Returns 'true' if this property cannot be changed, only retrieved.
Definition: YProperty.h:77
A push button; may have an icon, and a F-key shortcut.
Definition: YPushButton.h:38
virtual void setRole(YButtonRole role)
Set a predefined role for this button.
Definition: YPushButton.cc:154
virtual void setDefaultButton(bool def=true)
Make this button the default button.
Definition: YPushButton.cc:98
virtual void addItems(const YItemCollection &itemCollection)
Add multiple items.
Base class for UI Exceptions.
Definition: YUIException.h:298
static YWidgetFactory * widgetFactory()
Return the widget factory that provides all the createXY() methods for standard (mandatory,...
Definition: YUI.cc:132
Abstract base class of all UI widgets.
Definition: YWidget.h:55
YDialog * findDialog()
Traverse up the widget hierarchy and find the dialog this widget belongs to.
Definition: YWidget.cc:376
virtual const YPropertySet & propertySet()
Return this class's property set.
Definition: YWidget.cc:395
void setNotify(bool notify=true)
Sets the Notify property.
Definition: YWidget.cc:522
virtual bool setProperty(const std::string &propertyName, const YPropertyValue &val)
Set a property.
Definition: YWidget.cc:432
virtual YPropertyValue getProperty(const std::string &propertyName)
Get a property.
Definition: YWidget.cc:457