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