Salome HOME
21a286c11f2bab8a796c751036bfa01689f35ca7
[modules/gui.git] / src / Qtx / QtxListBox.cxx
1 //  Copyright (C) 2007-2008  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
3 //  Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 //  CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
5 //
6 //  This library is free software; you can redistribute it and/or
7 //  modify it under the terms of the GNU Lesser General Public
8 //  License as published by the Free Software Foundation; either
9 //  version 2.1 of the License.
10 //
11 //  This library is distributed in the hope that it will be useful,
12 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
13 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 //  Lesser General Public License for more details.
15 //
16 //  You should have received a copy of the GNU Lesser General Public
17 //  License along with this library; if not, write to the Free Software
18 //  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
19 //
20 //  See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 //
22 // File:      QtxListBox.cxx
23 // Author:    Sergey TELKOV
24 //
25 #include "QtxListBox.h"
26
27 #include <qpixmap.h>
28 #include <qlineedit.h>
29
30 /*!
31   Constructor
32 */
33 QtxListBox::QtxListBox( QWidget* parent, const char* name, WFlags f )
34 : QListBox( parent, name, f ),
35 myEditor( 0 ),
36 myEditIndex( -1 ),
37 myEditState( false ),
38 myEditDefault( true ),
39 myModifEnabled( true )
40 {
41   connect( this, SIGNAL( contentsMoving( int, int ) ),
42            this, SLOT( onContentsMoving( int, int ) ) );
43 }
44
45 /*!
46   Destructor
47 */
48 QtxListBox::~QtxListBox()
49 {
50 }
51
52 /*!
53   \return true if editing is enabled
54 */
55 bool QtxListBox::isEditEnabled() const
56 {
57   return myEditState;
58 }
59
60 /*!
61   Enables/disables editing
62   \param on - new state
63 */
64 void QtxListBox::setEditEnabled( bool on )
65 {
66   if ( isEditEnabled() == on )
67     return;
68
69   myEditState = on;
70
71   if ( !isEditEnabled() )
72     endEdition( defaultEditAction() );
73 }
74
75 /*!
76   \return default edit action
77   \sa setDefaultEditAction()
78 */
79 bool QtxListBox::defaultEditAction() const
80 {
81   return myEditDefault;
82 }
83
84 /*!
85   Changes default edit action. 
86   Pressing of ENTER button always accepts new value of edited item.
87   But other ways, such as focus out or edition of other item accepts
88   new value of edited item only if "default edit action" is true
89   \param def - new value
90 */
91 void QtxListBox::setDefaultEditAction( bool def )
92 {
93   myEditDefault = def;
94 }
95
96 /*!
97   \return modification enabled state
98   \sa setModificationEnabled()
99 */
100 bool QtxListBox::isModificationEnabled() const
101 {
102   return myModifEnabled;
103 }
104
105 /*!
106   Changes "modification enabled" state
107   If it is true, then pressing of CTRL + { Up, Down, Home, End } allows move items in list
108   \param on - new state
109 */
110 void QtxListBox::setModificationEnabled( bool on )
111 {
112   myModifEnabled = on;
113 }
114
115 /*!
116   \return current edited item
117 */
118 QListBoxItem* QtxListBox::editedItem() const
119 {
120   return item( editedIndex() );
121 }
122
123 /*!
124   \return current edited index
125 */
126 int QtxListBox::editedIndex() const
127 {
128   return myEditIndex;
129 }
130
131 /*!
132   Starts edition of item
133   \param idx - index of item
134 */
135 void QtxListBox::startEdition( const int idx )
136 {
137   if ( idx < 0 || editedIndex() == idx || !isEditEnabled() )
138     return;
139
140   QLineEdit* ed = editor();
141   if ( !ed )
142     return;
143
144   endEdition( defaultEditAction() );
145
146   myEditIndex = idx;
147
148   ensureItemVisible( myEditIndex );
149
150   ed->setText( text( myEditIndex ) );
151   updateEditor();
152   ed->show();
153
154   ed->setFocus();
155 }
156
157 /*!
158   Starts edition of item
159   \param item - item to be edited
160 */
161 void QtxListBox::startEdition( const QListBoxItem* item )
162 {
163   startEdition( index( item ) );
164 }
165
166 /*!
167   Finishes edition of item
168   \param action - if it is true, then new values must be accepted
169 */
170 void QtxListBox::endEdition( const bool action )
171 {
172   int idx = editedIndex();
173   QLineEdit* ed = editor();
174
175   if ( idx < 0 || !ed )
176     return;
177
178   myEditIndex = -1;
179
180   ed->hide();
181
182   if ( action )
183   {
184     int cur = currentItem();
185
186     if ( pixmap( idx ) )
187       changeItem( *pixmap( idx ), ed->text(), idx );
188     else
189       changeItem( ed->text(), idx );
190
191     setCurrentItem( cur );
192
193     emit itemEdited( idx );
194     emit itemEdited( item( idx ) );
195   }
196 }
197
198 /*!
199   Ensures that the item is visible.
200   \param idx - index of item
201 */
202 void QtxListBox::ensureItemVisible( const int idx )
203 {
204   if ( idx < 0 )
205     return;
206
207   if ( itemVisible( idx ) )
208     return;
209
210   setTopItem( idx );
211 }
212
213 /*!
214   Ensures that the item is visible.
215   \param item - item to be made visible
216 */
217 void QtxListBox::ensureItemVisible( const QListBoxItem* item )
218 {
219   ensureItemVisible( index( item ) );
220 }
221
222 /*!
223   \return validator of item editor
224 */
225 const QValidator* QtxListBox::validator() const
226 {
227   const QValidator* v = 0;
228   if ( editor() )
229     v = editor()->validator();
230   return v;
231 }
232
233 /*!
234   Removes validator of item editor
235 */
236 void QtxListBox::clearValidator()
237 {
238   if ( editor() )
239     editor()->clearValidator();
240 }
241
242 /*!
243   Changes validator of item editor
244   \param v - new validator
245 */
246 void QtxListBox::setValidator( const QValidator* v )
247 {
248   if ( editor() )
249     editor()->setValidator( v );
250 }
251
252 /*!
253   Moves item to top
254   \param idx - index of item
255 */
256 void QtxListBox::moveItemToTop( const int idx )
257 {
258   moveItem( idx, -idx );
259 }
260
261 /*!
262   Moves item to bottom
263   \param idx - index of item
264 */
265 void QtxListBox::moveItemToBottom( const int idx )
266 {
267   moveItem( idx, count() - idx );
268 }
269
270 /*!
271   Moves item
272   \param idx - index of item
273   \param step - changing of position
274 */
275 void QtxListBox::moveItem( const int idx, const int step )
276 {
277   QListBoxItem* i = item( idx );
278   if ( !i || step == 0 )
279     return;
280
281   QListBoxItem* cur = item( currentItem() );
282
283   takeItem( i );
284   insertItem( i, QMAX( 0, idx + step ) );
285
286   setCurrentItem( index( cur ) );
287
288   int pos = index( i );
289   if ( myEditIndex == idx )
290     myEditIndex = pos;
291
292   updateEditor();
293
294   if ( idx != pos )
295     emit itemMoved( idx, pos );
296 }
297
298 /*!
299   Inserts empty item
300   \param i - position of item (if it is less than 0, then current position is used)
301 */
302 void QtxListBox::createItem( const int i )
303 {
304   if ( !isEditEnabled() )
305     return;
306
307   int idx = i < 0 ? currentItem() : i;
308   idx = idx < 0 ? count() : idx;
309   idx = QMIN( (int)count(), idx );
310
311   insertItem( "", idx );
312   setCurrentItem( idx );
313   startEdition( idx );
314 }
315
316 /*!
317   Removes item
318   \param i - position of item (if it is less than 0, then current position is used)
319 */
320 void QtxListBox::deleteItem( const int i )
321 {
322   if ( !isEditEnabled() )
323     return;
324
325   int idx = i < 0 ? currentItem() : i;
326   if ( idx < 0 )
327     return;
328
329   if ( editedIndex() == idx )
330     endEdition( defaultEditAction() );
331
332   removeItem( idx );
333   updateEditor();
334 }
335
336 /*!
337   Scrolls the content so that the point is in the top-left corner.
338   \param x, y - point co-ordinates
339 */
340 void QtxListBox::setContentsPos( int x, int y )
341 {
342   QListBox::setContentsPos( x, y );
343
344   updateEditor();
345 }
346
347 /*!
348   Custom event filter, performs finish of edition on focus out, escape/return/enter pressing
349 */
350 bool QtxListBox::eventFilter( QObject* o, QEvent* e )
351 {
352   if ( editor() == o )
353   {
354     if ( e->type() == QEvent::FocusOut )
355       endEdition( defaultEditAction() );
356
357     if ( e->type() == QEvent::KeyPress )
358     {
359       QKeyEvent* ke = (QKeyEvent*)e;
360       if ( ke->key() == Key_Escape )
361         endEdition( false );
362       else if ( ke->key() == Key_Enter || ke->key() == Key_Return )
363         endEdition( true );
364     }
365   }
366
367   return QListBox::eventFilter( o, e );
368 }
369
370 /*!
371   Custom key press event handler
372   Allows to move items by CTRL + { Up, Down, Home, End }
373 */
374 void QtxListBox::keyPressEvent( QKeyEvent* e )
375 {
376   if ( e->key() == Key_Up && e->state() & ControlButton && isModificationEnabled() )
377     moveItem( currentItem(), -1 );
378   else if ( e->key() == Key_Down && e->state() & ControlButton && isModificationEnabled() )
379     moveItem( currentItem(), 1 );
380   else if ( e->key() == Key_Home && e->state() & ControlButton && isModificationEnabled() )
381     moveItemToTop( currentItem() );
382   else if ( e->key() == Key_End && e->state() & ControlButton && isModificationEnabled() )
383     moveItemToBottom( currentItem() );
384   else if ( e->key() == Key_Insert && e->state() & ControlButton )
385     createItem( currentItem() );
386   else if ( e->key() == Key_Delete && e->state() & ControlButton )
387     deleteItem( currentItem() );
388   else
389     QListBox::keyPressEvent( e );
390 }
391
392 /*!
393   Custom resize event handler
394 */
395 void QtxListBox::viewportResizeEvent( QResizeEvent* e )
396 {
397   QListBox::viewportResizeEvent( e );
398
399   updateEditor();
400 }
401
402 /*!
403   Custom mouse double click event handler
404 */
405 void QtxListBox::mouseDoubleClickEvent( QMouseEvent* e )
406 {
407   if ( isEditEnabled() )
408     startEdition( itemAt( e->pos() ) );
409   else
410     QListBox::mouseDoubleClickEvent( e );
411 }
412
413 /*!
414   Updates editor on contents moving
415 */
416 void QtxListBox::onContentsMoving( int, int )
417 {
418   updateEditor();
419 }
420
421 /*!
422   \return item editor
423 */
424 QLineEdit* QtxListBox::editor() const
425 {
426   if ( !myEditor )
427   {
428     QtxListBox* that = (QtxListBox*)this;
429     that->createEditor();
430   }
431   return myEditor;
432 }
433
434 /*!
435   Creates item editor
436 */
437 void QtxListBox::createEditor()
438 {
439   if ( myEditor )
440     return;
441
442   myEditor = new QLineEdit( viewport() );
443
444   myEditor->setLineWidth( 1 );
445   myEditor->setMidLineWidth( 0 );
446   myEditor->setFrameStyle( QFrame::Box | QFrame::Plain );
447   myEditor->installEventFilter( this );
448
449   myEditor->hide();
450
451   addChild( myEditor );
452 }
453
454 /*!
455   Updates item editor
456 */
457 void QtxListBox::updateEditor()
458 {
459   if ( !editedItem() || !editor() )
460     return;
461
462   QRect r = itemRect( editedItem() );
463   if ( !r.isValid() )
464     return;
465
466   int m = editor()->lineWidth();
467   r.addCoords( m, 0, 0, 0 );
468
469   const QPixmap* pix = pixmap( editedIndex() );
470   if ( pix )
471     r.addCoords( pix->width() + 2, 0, 0, 0 );
472
473   editor()->setGeometry( r );
474 }