libyui-qt  2.53.0
YQInputField.cc
1 /*
2  Copyright (C) 2000-2012 Novell, Inc
3  This library is free software; you can redistribute it and/or modify
4  it under the terms of the GNU Lesser General Public License as
5  published by the Free Software Foundation; either version 2.1 of the
6  License, or (at your option) version 3.0 of the License. This library
7  is distributed in the hope that it will be useful, but WITHOUT ANY
8  WARRANTY; without even the implied warranty of MERCHANTABILITY or
9  FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
10  License for more details. You should have received a copy of the GNU
11  Lesser General Public License along with this library; if not, write
12  to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
13  Floor, Boston, MA 02110-1301 USA
14 */
15 
16 
17 /*-/
18 
19  File: YQInputField.cc
20 
21  Author: Stefan Hundhammer <sh@suse.de>
22 
23  Textdomain "qt"
24 
25 /-*/
26 
27 
28 #include <qlineedit.h>
29 #define YUILogComponent "qt-ui"
30 #include <yui/YUILog.h>
31 
32 #include "utf8.h"
33 #include "YQUI.h"
34 #include <yui/YEvent.h>
35 #include "QY2CharValidator.h"
36 #include "YQInputField.h"
37 #include "YQi18n.h"
38 #include "YQSignalBlocker.h"
39 #include "YQWidgetCaption.h"
40 #include <QVBoxLayout>
41 
42 // Include low-level X headers AFTER Qt headers:
43 // X.h pollutes the global namespace (!!!) with pretty useless #defines
44 // like "Above", "Below" etc. that clash with some Qt headers.
45 #include <X11/X.h> // CapsLock detection
46 #include <X11/Xlib.h> // CapsLock detection
47 #include <X11/keysym.h> // CapsLock detection
48 
49 using std::string;
50 using std::endl;
51 
52 
53 
54 YQInputField::YQInputField( YWidget * parent,
55  const string & label,
56  bool passwordMode )
57  : QFrame( (QWidget *) parent->widgetRep() )
58  , YInputField( parent, label, passwordMode )
59  , _validator(0)
60  , _displayingCapsLockWarning( false )
61 {
62  QVBoxLayout* layout = new QVBoxLayout( this );
63  setLayout( layout );
64 
65  setWidgetRep( this );
66 
67  layout->setSpacing( YQWidgetSpacing );
68  layout->setMargin( YQWidgetMargin );
69 
70  _caption = new YQWidgetCaption( this, label );
71  YUI_CHECK_NEW( _caption );
72  layout->addWidget( _caption );
73 
74  _qt_lineEdit = new YQRawLineEdit( this );
75  YUI_CHECK_NEW( _qt_lineEdit );
76  layout->addWidget( _qt_lineEdit );
77 
78  _caption->setBuddy( _qt_lineEdit );
79 
80  connect( _qt_lineEdit, &pclass(_qt_lineEdit)::textChanged,
81  this, &pclass(this)::changed );
82 
83  if ( passwordMode )
84  {
85  _qt_lineEdit->setEchoMode( QLineEdit::Password );
86 
87  connect( _qt_lineEdit, &pclass(_qt_lineEdit)::capsLockActivated,
88  this, &pclass(this)::displayCapsLockWarning );
89 
90  connect( _qt_lineEdit, &pclass(_qt_lineEdit)::capsLockDeactivated,
91  this, &pclass(this)::clearCapsLockWarning );
92  }
93 }
94 
95 
97 {
98  return toUTF8( _qt_lineEdit->text() );
99 }
100 
101 
102 void YQInputField::setValue( const string & newText )
103 {
104  QString text = fromUTF8( newText );
105 
106  if ( isValidText( text ) )
107  {
108  YQSignalBlocker sigBlocker( _qt_lineEdit );
109  _qt_lineEdit->setText( text );
110  }
111  else
112  {
113  yuiError() << this << ": Rejecting invalid value \"" << newText << "\"" << endl;
114  }
115 }
116 
117 
118 void YQInputField::setEnabled( bool enabled )
119 {
120  _qt_lineEdit->setEnabled( enabled );
121  _caption->setEnabled( enabled );
122  YWidget::setEnabled( enabled );
123 }
124 
125 
127 {
128  int minSize = shrinkable() ? 30 : 200;
129  int hintWidth = !_caption->isHidden()
130  ? _caption->sizeHint().width() + 2 * YQWidgetMargin
131  : 0;
132 
133  return std::max( minSize, hintWidth );
134 }
135 
136 
138 {
139  return sizeHint().height();
140 }
141 
142 
143 void YQInputField::setSize( int newWidth, int newHeight )
144 {
145  resize( newWidth, newHeight );
146 }
147 
148 
149 void YQInputField::setLabel( const string & label )
150 {
151  _caption->setText( label );
152  YInputField::setLabel( label );
153 }
154 
155 
156 bool YQInputField::isValidText( const QString & txt ) const
157 {
158  if ( ! _validator )
159  return true;
160 
161  int pos = 0;
162  QString text( txt ); // need a non-const QString &
163 
164  return _validator->validate( text, pos ) == QValidator::Acceptable;
165 }
166 
167 
168 void YQInputField::setValidChars( const string & newValidChars )
169 {
170  if ( _validator )
171  {
172  _validator->setValidChars( fromUTF8( newValidChars ) );
173  }
174  else
175  {
176  _validator = new QY2CharValidator( fromUTF8( newValidChars ), this );
177  _qt_lineEdit->setValidator( _validator );
178 
179  // No need to delete the validator in the destructor - Qt will take
180  // care of that since it's a QObject with a parent!
181  }
182 
183  if ( ! isValidText( _qt_lineEdit->text() ) )
184  {
185  yuiError() << this << ": Old value \"" << _qt_lineEdit->text()
186  << "\" invalid according to new ValidChars \"" << newValidChars
187  << "\" - deleting"
188  << endl;
189 
190  _qt_lineEdit->setText( "" );
191  }
192 
193  YInputField::setValidChars( newValidChars );
194 }
195 
197 {
198  _qt_lineEdit->setMaxLength( len );
199  YInputField::setInputMaxLength( len );
200 }
201 
203 {
204  _qt_lineEdit->setFocus();
205  _qt_lineEdit->selectAll();
206 
207  return true;
208 }
209 
210 
211 void YQInputField::changed( const QString & )
212 {
213  if ( notify() )
214  YQUI::ui()->sendEvent( new YWidgetEvent( this, YEvent::ValueChanged ) );
215 }
216 
217 
219 {
220  yuiMilestone() << "warning" << endl;
221  if ( _displayingCapsLockWarning )
222  return;
223 
224  if ( _qt_lineEdit->echoMode() == QLineEdit::Normal )
225  return;
226 
227  // Translators: This is a very short warning that the CapsLock key
228  // is active while trying to type in a password field. This warning
229  // replaces the normal label (caption) of that password field while
230  // CapsLock is active, so please keep it short. Please don't translate it
231  // at all if the term "CapsLock" can reasonably expected to be understood
232  // by the target audience.
233  //
234  // In particular, please don't translate this to death in German.
235  // Simply leave it.
236 
237  _caption->setText( _( "CapsLock!" ) );
238  _displayingCapsLockWarning = true;
239 }
240 
241 
243 {
244  yuiMilestone() << "warning off " << endl;
245  if ( ! _displayingCapsLockWarning )
246  return;
247 
248  if ( _qt_lineEdit->echoMode() == QLineEdit::Normal )
249  return;
250 
251  _caption->setText( label() );
252  _displayingCapsLockWarning = false;
253 }
254 
255 
256 bool YQRawLineEdit::x11Event( XEvent * event )
257 {
258  // Qt (3.x) does not have support for the CapsLock key.
259  // All other modifiers (Shift, Control, Meta) are propagated via
260  // Qt's events, but for some reason, CapsLock is not.
261  //
262  // So let's examine the raw X11 event here to check for the
263  // CapsLock status. All events are really handled on the parent class
264  // (QWidget) level, though. We only peek into the modifier states.
265 
266  if ( event )
267  {
268  bool oldCapsLockActive = _capsLockActive;
269 
270  switch ( event->type )
271  {
272  case KeyPress:
273  _capsLockActive = (bool) ( event->xkey.state & LockMask );
274  break;
275 
276  case KeyRelease:
277 
278  _capsLockActive = (bool) ( event->xkey.state & LockMask );
279 
280  if ( _capsLockActive && oldCapsLockActive )
281  {
282  KeySym key = XLookupKeysym( &(event->xkey), 0 );
283 
284  if ( key == XK_Caps_Lock ||
285  key == XK_Shift_Lock )
286  {
287  yuiMilestone() << "CapsLock released" << endl;
288  _capsLockActive = false;
289  }
290  }
291 
292  if ( _capsLockActive )
293  yuiDebug() << "Key event; caps lock: "
294  << std::boolalpha << _capsLockActive << std::noboolalpha
295  << endl;
296  break;
297 
298  case ButtonPress:
299  case ButtonRelease:
300  _capsLockActive = (bool) ( event->xbutton.state & LockMask );
301  break;
302 
303  case EnterNotify:
304  _capsLockActive = (bool) ( event->xcrossing.state & LockMask );
305  break;
306 
307  case LeaveNotify:
308  case FocusOut:
309  _capsLockActive = false;
310  emit capsLockDeactivated();
311  break;
312 
313  default:
314  break;
315  }
316 
317  if ( oldCapsLockActive != _capsLockActive )
318  {
319  yuiMilestone() << "Emitting warning" << endl;
320 
321  if ( _capsLockActive )
322  emit capsLockActivated();
323  else
324  emit capsLockDeactivated();
325  }
326  }
327 
328  return false; // handle this event at the Qt level
329 }
YQSignalBlocker
Helper class to block Qt signals for QWidgets or QObjects as long as this object exists.
Definition: YQSignalBlocker.h:37
QY2CharValidator
Definition: QY2CharValidator.h:35
YQUI::sendEvent
void sendEvent(YEvent *event)
Widget event handlers (slots) call this when an event occured that should be the answer to a UserInpu...
Definition: YQUI.cc:480
YQInputField::setInputMaxLength
virtual void setInputMaxLength(int numberOfChars)
Specify the amount of characters which can be inserted.
Definition: YQInputField.cc:196
QY2CharValidator::setValidChars
void setValidChars(const QString &newValidChars)
Set the valid input characters.
Definition: QY2CharValidator.h:66
YQInputField::setLabel
virtual void setLabel(const std::string &label)
Set the label (the caption above the input field).
Definition: YQInputField.cc:149
YQInputField::setEnabled
virtual void setEnabled(bool enabled)
Set enabled/disabled state.
Definition: YQInputField.cc:118
YQInputField::setKeyboardFocus
virtual bool setKeyboardFocus()
Accept the keyboard focus.
Definition: YQInputField.cc:202
YQInputField::displayCapsLockWarning
void displayCapsLockWarning()
Display a warning that CapsLock is active: Replace the label with "CapsLock!".
Definition: YQInputField.cc:218
YQRawLineEdit
Helper class that can obtain the CapsLock status, too.
Definition: YQInputField.h:168
YQWidgetCaption::setText
virtual void setText(const std::string &newText)
Change the text and handle visibility: If the new text is empty, hide this widget.
Definition: YQWidgetCaption.cc:59
QY2CharValidator::validate
virtual State validate(QString &input, int &pos) const
Check user input.
Definition: QY2CharValidator.cc:51
YQInputField::preferredHeight
virtual int preferredHeight()
Preferred height of the widget.
Definition: YQInputField.cc:137
YQUI::ui
static YQUI * ui()
Access the global Qt-UI.
Definition: YQUI.h:83
YQInputField::isValidText
bool isValidText(const QString &text) const
Returns 'true' if a given text is valid according to ValidChars.
Definition: YQInputField.cc:156
YQInputField::setSize
virtual void setSize(int newWidth, int newHeight)
Set the new size of the widget.
Definition: YQInputField.cc:143
YQInputField::preferredWidth
virtual int preferredWidth()
Preferred width of the widget.
Definition: YQInputField.cc:126
YQRawLineEdit::x11Event
bool x11Event(XEvent *event)
X11 raw event handler.
Definition: YQInputField.cc:256
YQWidgetCaption
Helper class for captions (labels) above a widget: Takes care of hiding itself when its text is empty...
Definition: YQWidgetCaption.h:39
YQInputField::clearCapsLockWarning
void clearCapsLockWarning()
Clear the CapsLock warning: Restore old label.
Definition: YQInputField.cc:242
YQInputField::value
virtual std::string value()
Get the current value (the text entered by the user or set from the outside) of this input field.
Definition: YQInputField.cc:96
YQInputField::changed
void changed(const QString &)
Triggered when the text in the InputField changes.
Definition: YQInputField.cc:211
YQInputField::setValidChars
virtual void setValidChars(const std::string &validChars)
Set the valid input characters.
Definition: YQInputField.cc:168
YQInputField::YQInputField
YQInputField(YWidget *parent, const std::string &label, bool passwordMode=false)
Constructor.
Definition: YQInputField.cc:54
YQInputField::setValue
virtual void setValue(const std::string &text)
Set the current value (the text entered by the user or set from the outside) of this input field.
Definition: YQInputField.cc:102