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