]> icculus.org git repositories - duncan/yast2-qt4.git/blob - src/YQInputField.cc
disabling the style for now as the theming causes terrible
[duncan/yast2-qt4.git] / src / YQInputField.cc
1 /*---------------------------------------------------------------------\
2 |                                                                      |
3 |                      __   __    ____ _____ ____                      |
4 |                      \ \ / /_ _/ ___|_   _|___ \                     |
5 |                       \ V / _` \___ \ | |   __) |                    |
6 |                        | | (_| |___) || |  / __/                     |
7 |                        |_|\__,_|____/ |_| |_____|                    |
8 |                                                                      |
9 |                               core system                            |
10 |                                                        (C) SuSE GmbH |
11 \----------------------------------------------------------------------/
12
13   File:       YQInputField.cc
14
15   Author:     Stefan Hundhammer <sh@suse.de>
16
17   Textdomain "packages-qt"
18
19 /-*/
20
21
22 #include <qlineedit.h>
23 #define y2log_component "qt-ui"
24 #include <ycp/y2log.h>
25
26 using std::max;
27
28 #include "utf8.h"
29 #include "YQUI.h"
30 #include "YEvent.h"
31 #include "QY2CharValidator.h"
32 #include "YQInputField.h"
33 #include "YQi18n.h"
34 #include "YQSignalBlocker.h"
35 #include "YQWidgetCaption.h"
36 #include <QVBoxLayout>
37
38 // Include low-level X headers AFTER Qt headers:
39 // X.h pollutes the global namespace (!!!) with pretty useless #defines
40 // like "Above", "Below" etc. that clash with some Qt headers.
41 #include <X11/X.h>              // CapsLock detection
42 #include <X11/Xlib.h>           // CapsLock detection
43 #include <X11/keysym.h>         // CapsLock detection
44
45 using std::string;
46
47
48
49 YQInputField::YQInputField( YWidget *           parent,
50                             const string &      label,
51                             bool                passwordMode )
52     : QFrame( (QWidget *) parent->widgetRep() )
53     , YInputField( parent, label, passwordMode )
54     , _validator(0)
55     , _displayingCapsLockWarning( false )
56 {
57     QVBoxLayout* layout = new QVBoxLayout( this );
58     setLayout( layout );
59
60     setWidgetRep( this );
61
62     layout->setSpacing( YQWidgetSpacing );
63     layout->setMargin( YQWidgetMargin );
64
65     _caption = new YQWidgetCaption( this, label );
66     YUI_CHECK_NEW( _caption );
67     layout->addWidget( _caption );
68
69     _qt_lineEdit = new YQRawLineEdit( this );
70     YUI_CHECK_NEW( _qt_lineEdit );
71     layout->addWidget( _qt_lineEdit );
72
73     _caption->setBuddy( _qt_lineEdit );
74
75     connect( _qt_lineEdit, SIGNAL( textChanged( const QString & ) ),
76              this,         SLOT  ( changed    ( const QString & ) ) );
77
78     if ( passwordMode )
79     {
80         _qt_lineEdit->setEchoMode( QLineEdit::Password );
81
82         connect( _qt_lineEdit,  SIGNAL( capsLockActivated() ),
83                  this,          SLOT  ( displayCapsLockWarning() ) );
84
85         connect( _qt_lineEdit,  SIGNAL( capsLockDeactivated() ),
86                  this,          SLOT  ( clearCapsLockWarning() ) );
87     }
88 }
89
90
91 string YQInputField::value()
92 {
93     return toUTF8( _qt_lineEdit->text() );
94 }
95
96
97 void YQInputField::setValue( const string & newText )
98 {
99     QString text = fromUTF8( newText );
100
101     if ( isValidText( text ) )
102     {
103         YQSignalBlocker sigBlocker( _qt_lineEdit );
104         _qt_lineEdit->setText( text );
105     }
106     else
107     {
108         y2error( "%s \"%s\": Rejecting invalid value \"%s\"",
109                  widgetClass(), debugLabel().c_str(), newText.c_str() );
110     }
111 }
112
113
114 void YQInputField::setEnabled( bool enabled )
115 {
116     _qt_lineEdit->setEnabled( enabled );
117     _caption->setEnabled( enabled );
118     YWidget::setEnabled( enabled );
119 }
120
121
122 int YQInputField::preferredWidth()
123 {
124     int minSize   = shrinkable() ? 30 : 200;
125     int hintWidth = !_caption->isHidden()
126         ? _caption->sizeHint().width() + 2 * YQWidgetMargin
127         : 0;
128
129     return max( minSize, hintWidth );
130 }
131
132
133 int YQInputField::preferredHeight()
134 {
135     return sizeHint().height();
136 }
137
138
139 void YQInputField::setSize( int newWidth, int newHeight )
140 {
141     resize( newWidth, newHeight );
142 }
143
144
145 void YQInputField::setLabel( const string & label )
146 {
147     _caption->setText( label );
148     YInputField::setLabel( label );
149 }
150
151
152 bool YQInputField::isValidText( const QString & txt ) const
153 {
154     if ( ! _validator )
155         return true;
156
157     int pos = 0;
158     QString text( txt );        // need a non-const QString &
159
160     return _validator->validate( text, pos ) == QValidator::Acceptable;
161 }
162
163
164 void YQInputField::setValidChars( const string & newValidChars )
165 {
166     if ( _validator )
167     {
168         _validator->setValidChars( fromUTF8( newValidChars ) );
169     }
170     else
171     {
172         _validator = new QY2CharValidator( fromUTF8( newValidChars ), this );
173         _qt_lineEdit->setValidator( _validator );
174
175         // No need to delete the validator in the destructor - Qt will take
176         // care of that since it's a QObject with a parent!
177     }
178
179     if ( ! isValidText( _qt_lineEdit->text() ) )
180     {
181         y2error( "Old value \"%s\" of %s \"%s\" invalid according to ValidChars \"%s\" - deleting",
182                  qPrintable(_qt_lineEdit->text()),
183                  widgetClass(), debugLabel().c_str(),
184                  newValidChars.c_str() );
185         _qt_lineEdit->setText( "" );
186     }
187
188     YInputField::setValidChars( newValidChars );
189 }
190
191 void YQInputField::setInputMaxLength( int len )
192 {
193     _qt_lineEdit->setMaxLength( len );
194     YInputField::setInputMaxLength( len );
195 }
196
197 bool YQInputField::setKeyboardFocus()
198 {
199     _qt_lineEdit->setFocus();
200     _qt_lineEdit->selectAll();
201
202     return true;
203 }
204
205
206 void YQInputField::changed( const QString & )
207 {
208     if ( notify() )
209         YQUI::ui()->sendEvent( new YWidgetEvent( this, YEvent::ValueChanged ) );
210 }
211
212
213 void YQInputField::displayCapsLockWarning()
214 {
215     y2milestone( "warning" );
216     if ( _displayingCapsLockWarning )
217         return;
218
219     if ( _qt_lineEdit->echoMode() == QLineEdit::Normal )
220         return;
221
222     // Translators: This is a very short warning that the CapsLock key
223     // is active while trying to type in a password field. This warning
224     // replaces the normal label (caption) of that password field while
225     // CapsLock is active, so please keep it short. Please don't translate it
226     // at all if the term "CapsLock" can reasonably expected to be understood
227     // by the target audience.
228     //
229     // In particular, please don't translate this to death in German.
230     // Simply leave it.
231
232     _caption->setText( _( "CapsLock!" ) );
233     _displayingCapsLockWarning = true;
234 }
235
236
237 void YQInputField::clearCapsLockWarning()
238 {
239     y2milestone( "warning off " );
240     if ( ! _displayingCapsLockWarning )
241         return;
242
243     if ( _qt_lineEdit->echoMode() == QLineEdit::Normal )
244         return;
245
246     _caption->setText( label() );
247     _displayingCapsLockWarning = false;
248 }
249
250
251 bool YQRawLineEdit::x11Event( XEvent * event )
252 {
253     // Qt (3.x) does not have support for the CapsLock key.
254     // All other modifiers (Shift, Control, Meta) are propagated via
255     // Qt's events, but for some reason, CapsLock is not.
256     //
257     // So let's examine the raw X11 event here to check for the
258     // CapsLock status. All events are really handled on the parent class
259     // (QWidget) level, though. We only peek into the modifier states.
260
261     if ( event )
262     {
263         bool oldCapsLockActive = _capsLockActive;
264
265         switch ( event->type )
266         {
267             case KeyPress:
268                 _capsLockActive = (bool) ( event->xkey.state & LockMask );
269                 break;
270
271             case KeyRelease:
272
273                 _capsLockActive = (bool) ( event->xkey.state & LockMask );
274
275                 if ( _capsLockActive && oldCapsLockActive )
276                 {
277                     KeySym key = XLookupKeysym( &(event->xkey), 0 );
278
279                     if ( key == XK_Caps_Lock ||
280                          key == XK_Shift_Lock  )
281                     {
282                         y2milestone( "CapsLock released" );
283                         _capsLockActive = false;
284                     }
285                 }
286
287                 y2debug( "Key event; caps lock: %s", _capsLockActive ? "on" : "off" );
288                 break;
289
290             case ButtonPress:
291             case ButtonRelease:
292                 _capsLockActive = (bool) ( event->xbutton.state & LockMask );
293                 break;
294
295             case EnterNotify:
296                 _capsLockActive = (bool) ( event->xcrossing.state & LockMask );
297                 break;
298
299             case LeaveNotify:
300             case FocusOut:
301                 _capsLockActive = false;
302                 emit capsLockDeactivated();
303                 break;
304
305             default:
306                 break;
307         }
308
309         if ( oldCapsLockActive != _capsLockActive )
310         {
311             y2milestone( "Emitting warning" );
312
313             if ( _capsLockActive )
314                 emit capsLockActivated();
315             else
316                 emit capsLockDeactivated();
317         }
318     }
319
320     return false; // handle this event at the Qt level
321 }
322
323
324 #include "YQInputField.moc"