Salome HOME
1acd19253f617f9beade0655ce7a71caf465322f
[modules/gui.git] / src / Qtx / QtxTable.cxx
1 // Copyright (C) 2007-2022  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, 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:      QtxTable.cxx
24 // Author:    Sergey TELKOV
25 //
26 #include "QtxTable.h"
27
28 #ifndef QT_NO_TABLE
29
30 #include <qlineedit.h>
31
32 /*!
33   Constructor
34 */
35 QtxTable::QtxTable( QWidget* parent, const char* name )
36 : QTable( parent, name ),
37 myHeaderEditor( 0 ),
38 myEditedHeader( 0 ),
39 myEditedSection( -1 )
40 {
41   connect( verticalHeader(), SIGNAL( sizeChange( int, int, int ) ),
42            this, SLOT( onHeaderSizeChange( int, int, int ) ) );
43   connect( horizontalHeader(), SIGNAL( sizeChange( int, int, int ) ),
44            this, SLOT( onHeaderSizeChange( int, int, int ) ) );
45   connect( verticalScrollBar(), SIGNAL( valueChanged( int ) ), this, SLOT( onScrollBarMoved( int ) ) );
46   connect( horizontalScrollBar(), SIGNAL( valueChanged( int ) ), this, SLOT( onScrollBarMoved( int ) ) );
47 }
48
49 /*!
50   Constructor
51 */
52 QtxTable::QtxTable( int numRows, int numCols, QWidget* parent, const char* name )
53 : QTable( numRows, numCols, parent, name ),
54 myHeaderEditor( 0 ),
55 myEditedHeader( 0 ),
56 myEditedSection( -1 )
57 {
58   connect( verticalHeader(), SIGNAL( sizeChange( int, int, int ) ),
59            this, SLOT( onHeaderSizeChange( int, int, int ) ) );
60   connect( horizontalHeader(), SIGNAL( sizeChange( int, int, int ) ),
61            this, SLOT( onHeaderSizeChange( int, int, int ) ) );
62   connect( verticalScrollBar(), SIGNAL( valueChanged( int ) ), this, SLOT( onScrollBarMoved( int ) ) );
63   connect( horizontalScrollBar(), SIGNAL( valueChanged( int ) ), this, SLOT( onScrollBarMoved( int ) ) );
64 }
65
66 /*!
67   Destructor
68 */
69 QtxTable::~QtxTable()
70 {
71 }
72
73 /*!
74   \return true if header is editable
75   \param o - header orientation
76 */
77 bool QtxTable::headerEditable( Orientation o ) const
78 {
79   return myHeaderEditable.contains( o ) ? myHeaderEditable[o] : false;
80 }
81
82 /*!
83   Changes editable state of header
84   \param o - header orientation
85   \param on - new state
86 */
87 void QtxTable::setHeaderEditable( Orientation o, const bool on )
88 {
89   if ( headerEditable( o ) == on )
90     return;
91
92   myHeaderEditable.insert( o, on );
93
94   QHeader* hdr = header( o );
95
96   if ( !on && myEditedHeader == hdr )
97     endHeaderEdit( false );
98
99   if ( on )
100     hdr->installEventFilter( this );
101   else
102     hdr->removeEventFilter( this );
103 }
104
105 /*!
106   Starts edition of header
107   \param o - header orientation
108   \param sec - column/row
109 */
110 bool QtxTable::editHeader( Orientation o, const int sec )
111 {
112   return beginHeaderEdit( o, sec );
113 }
114
115 /*!
116   Finishes edition of header
117   \param accept - whether new value must be accepted
118 */
119 void QtxTable::endEditHeader( const bool accept )
120 {
121   endHeaderEdit( accept );
122 }
123
124 /*!
125   Finishes edition and hides table
126 */
127 void QtxTable::hide()
128 {
129   endHeaderEdit();
130
131   QTable::hide();
132 }
133
134 /*!
135   Custom event filter
136   Starts edition of header by double click
137   Finishes edition by escape/return/enter pressing
138 */
139 bool QtxTable::eventFilter( QObject* o, QEvent* e )
140 {
141   if ( e->type() == QEvent::MouseButtonDblClick )
142   {
143     QMouseEvent* me = (QMouseEvent*)e;
144     if ( o == horizontalHeader() )
145     {
146       beginHeaderEdit( Horizontal, me->pos() );
147       return true;
148     }
149     else if ( o == verticalHeader() )
150     {
151       beginHeaderEdit( Vertical, me->pos() );
152       return true;
153     }
154   }
155
156   if ( o == myHeaderEditor && e->type() == QEvent::KeyPress && isHeaderEditing() )
157   {
158           QKeyEvent* ke = (QKeyEvent*)e;
159     if ( ke->key() == Key_Escape )
160     {
161       endHeaderEdit( false );
162       return true;
163     }
164
165     if ( ke->key() == Key_Return || ke->key() == Key_Enter )
166     {
167       endHeaderEdit( true );
168       return true;
169     }
170
171     return false;
172   }
173
174   if ( o == myHeaderEditor && e->type() == QEvent::FocusOut &&
175        isHeaderEditing() && ((QFocusEvent*)e)->reason() != QFocusEvent::Popup )
176   {
177                 endHeaderEdit();
178                 return true;
179   }
180
181   if ( e->type() == QEvent::Wheel && isHeaderEditing() )
182     return true;
183
184   return QTable::eventFilter( o, e );
185 }
186
187 /*!
188   SLOT: called on scroll
189 */
190 void QtxTable::onScrollBarMoved( int )
191 {
192   updateHeaderEditor();
193 }
194
195 /*!
196   SLOT: called on header size changing
197 */
198 void QtxTable::onHeaderSizeChange( int, int, int )
199 {
200   if ( sender() == myEditedHeader )
201     updateHeaderEditor();
202 }
203
204 /*!
205   Custom resize event handler
206 */
207 void QtxTable::resizeEvent( QResizeEvent* e )
208 {
209   QTable::resizeEvent( e );
210
211   updateHeaderEditor();
212 }
213
214 /*!
215   Starts edition of header
216   \param o - header orientation
217   \param sec - column/row
218 */
219 bool QtxTable::beginHeaderEdit( Orientation o, const int section )
220 {
221   if ( !headerEditable( o ) || !header( o ) || !header( o )->isVisibleTo( this ) )
222     return false;
223
224   endHeaderEdit();
225
226   QHeader* hdr = header( o );
227
228   QRect r = headerSectionRect( hdr, section );
229   if ( !r.isValid() )
230     return false;
231
232   if ( o == Horizontal )
233     r.setLeft( QMAX( r.left(), leftMargin() ) );
234   else
235     r.setTop( QMAX( r.top(), topMargin() ) );
236
237   myHeaderEditor = createHeaderEditor( hdr, section );
238   if ( !myHeaderEditor )
239     return false;
240
241   myEditedHeader = hdr;
242   myEditedSection = section;
243
244   myHeaderEditor->reparent( this, QPoint( 0, 0 ), false );
245
246   updateHeaderEditor();
247
248   myHeaderEditor->show();
249
250   myHeaderEditor->setActiveWindow();
251   myHeaderEditor->setFocus();
252
253   myHeaderEditor->installEventFilter( this );
254
255   return true;
256 }
257
258 /*!
259   Finishes edition of header
260   \param accept - whether new value must be accepted
261 */
262 void QtxTable::endHeaderEdit( const bool accept )
263 {
264   if ( !isHeaderEditing() )
265     return;
266
267   QString oldTxt = myEditedHeader ? myEditedHeader->label( myEditedSection ) : QString();
268
269   if ( accept && myEditedHeader )
270     setHeaderContentFromEditor( myEditedHeader, myEditedSection, myHeaderEditor );
271
272   QString newTxt = myEditedHeader ? myEditedHeader->label( myEditedSection ) : QString();
273
274   int sec = myEditedSection;
275   QHeader* hdr = myEditedHeader;
276
277   myEditedHeader = 0;
278   myEditedSection = -1;
279
280   myHeaderEditor->hide();
281   myHeaderEditor->deleteLater();
282   myHeaderEditor = 0;
283
284   if ( oldTxt != newTxt )
285   {
286     emit headerEdited( hdr, sec );
287     emit headerEdited( hdr == horizontalHeader() ? Horizontal : Vertical, sec );
288   }
289 }
290
291 /*!
292   \return true if header is being edited
293 */
294 bool QtxTable::isHeaderEditing() const
295 {
296   return myHeaderEditor && myEditedHeader && myEditedSection != -1;
297 }
298
299 /*!
300   Creates and \return header editor
301   \param hdr - header
302   \param sec - column/row
303   \param init - init editor with value
304 */
305 QWidget* QtxTable::createHeaderEditor( QHeader* hdr, const int sec, const bool init )
306 {
307   QLineEdit* ed = new QLineEdit( 0 );
308
309   if ( init && hdr )
310     ed->setText( hdr->label( sec ) );
311
312   return ed;
313 }
314
315 /*!
316   Initialize editor with value
317   \param hdr - header
318   \param sec - column/row
319   \param editor - editor
320 */
321 void QtxTable::setHeaderContentFromEditor( QHeader* hdr, const int sec, QWidget* editor )
322 {
323   if ( !hdr || !editor )
324     return;
325
326   if ( editor->inherits( "QLineEdit" ) )
327     hdr->setLabel( sec, ((QLineEdit*)editor)->text() );
328 }
329
330 /*!
331   \return header
332   \param o - orientation
333 */
334 QHeader* QtxTable::header( Orientation o ) const
335 {
336   return o == Horizontal ? horizontalHeader() : verticalHeader();
337 }
338
339 /*!
340   Starts edition of header
341   \param o - header orientation
342   \param p - point
343 */
344 void QtxTable::beginHeaderEdit( Orientation o, const QPoint& p )
345 {
346   QHeader* hdr = header( o );
347   if ( !hdr )
348     return;
349
350   int pos = o == Horizontal ? p.x() : p.y();
351   int sec = hdr->sectionAt( hdr->offset() + pos );
352
353   beginHeaderEdit( o, sec );
354 }
355
356 /*!
357   \return rectangle of header section
358   \param hdr - header
359   \param sec - column/row
360 */
361 QRect QtxTable::headerSectionRect( QHeader* hdr, const int sec ) const
362 {
363   QRect r( -1, -1, -1, -1 );
364
365   if ( !hdr )
366     return r;
367
368   r = hdr->sectionRect( sec );
369   if ( r.isValid() )
370     r = QRect( mapFromGlobal( hdr->mapToGlobal( r.topLeft() ) ), r.size() );
371
372   return r;
373 }
374
375 /*!
376   Updates header editor
377 */
378 void QtxTable::updateHeaderEditor()
379 {
380   if ( !myHeaderEditor || !myEditedHeader || myEditedSection < 0 )
381     return;
382
383   QRect r = headerSectionRect( myEditedHeader, myEditedSection );
384   if ( !r.isValid() )
385     return;
386
387   if ( myEditedHeader == horizontalHeader() )
388   {
389     r.setLeft( QMAX( r.left(), leftMargin() ) );
390     r.setRight( QMIN( r.right(), width() - rightMargin() - 2 ) );
391   }
392   else
393   {
394     r.setTop( QMAX( r.top(), topMargin() ) );
395     r.setBottom( QMIN( r.bottom(), height() - bottomMargin() - 2 ) );
396   }
397
398   myHeaderEditor->resize( r.size() );
399   myHeaderEditor->move( r.topLeft() );
400 }
401
402 #endif