Salome HOME
5bbc1f79b2f47ca47bcbf1f74ce33749be37d08c
[modules/gui.git] / src / Qtx / QtxDialog.cxx
1 // Copyright (C) 2005  OPEN CASCADE, CEA/DEN, EDF R&D, PRINCIPIA R&D
2 // 
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either 
6 // version 2.1 of the License.
7 // 
8 // This library is distributed in the hope that it will be useful 
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of 
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU 
11 // Lesser General Public License for more details.
12 //
13 // You should have received a copy of the GNU Lesser General Public  
14 // License along with this library; if not, write to the Free Software 
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
16 //
17 // See http://www.salome-platform.org/
18 //
19 // File:      QtxDialog.cxx
20 // Author:    Sergey TELKOV
21
22 #include "QtxDialog.h"
23
24 #include "QtxGroupBox.h"
25
26 #include <qlabel.h>
27 #include <qframe.h>
28 #include <qlayout.h>
29 #include <qpushbutton.h>
30 #include <qapplication.h>
31
32 /*!
33         Class: QtxDialog::Area
34         Level: Internal
35 */
36 class QtxDialog::Area : public QFrame
37 {
38 public:
39         Area( Orientation, QtxDialog*, QWidget* = 0 );
40         virtual ~Area();
41
42         bool                     isBorderEnabled() const;
43         void                     setBorderEnabled( const bool );
44
45         void                     setBorderWidget( QLabel* );
46
47         void                     insertButton( QButton* );
48         void                     removeButton( QButton* );
49         bool                     contains( QButton* ) const;
50
51         int                      policy() const;
52         void                     setPolicy( const int );
53
54         void                     layoutButtons();
55
56         const QPtrList<QButton>& buttons() const;
57
58 private:
59         void                     updateBorder();
60
61 private:
62         QtxDialog*               myDlg;
63         QLabel*                  myLine;
64         bool                     myBorder;
65         int                      myPolicy;
66         QPtrList<QButton>        myButtons;
67         Orientation              myOrientation;
68 };
69
70 /*!
71   Contructor
72 */
73 QtxDialog::Area::Area( Orientation o, QtxDialog* dlg, QWidget* parent )
74 : QFrame( parent ),
75 myDlg( dlg ),
76 myLine( 0 ),
77 myBorder( false ),
78 myPolicy( Position ),
79 myOrientation( o )
80 {
81         if ( myOrientation == Qt::Horizontal )
82                 setSizePolicy( QSizePolicy( QSizePolicy::Preferred, QSizePolicy::Maximum ) );
83         else
84                 setSizePolicy( QSizePolicy( QSizePolicy::Maximum, QSizePolicy::Preferred ) );
85
86         hide();
87 }
88
89 /*!
90   Destructor
91 */
92 QtxDialog::Area::~Area()
93 {
94 }
95
96 /*!
97   Inserts button to area
98   \param b - button
99 */
100 void QtxDialog::Area::insertButton( QButton* b )
101 {
102         if ( !b || myButtons.findRef( b ) != -1 )
103                 return;
104
105         QWidget* parent = b->parentWidget();
106         if ( parent != this )
107                 b->reparent( this, 0, QPoint( 0, 0 ), b->isVisibleTo( parent ) );
108
109         myButtons.append( b );
110
111         if ( myDlg )
112                 myDlg->adjustButtons();
113         layoutButtons();
114
115         show();
116
117         updateBorder();
118 }
119
120 /*!
121   Removes button from area
122   \param b - button
123 */
124 void QtxDialog::Area::removeButton( QButton* b )
125 {
126         if ( !b )
127                 return;
128
129         myButtons.removeRef( b );
130
131         if ( myButtons.isEmpty() )
132                 hide();
133
134         updateBorder();
135
136         if ( myDlg )
137                 myDlg->adjustButtons();
138
139         layoutButtons();
140 }
141
142 /*!
143   \return true if area contains button
144   \param b - button
145 */
146 bool QtxDialog::Area::contains( QButton* b ) const
147 {
148         return myButtons.containsRef( b );
149 }
150
151 /*!
152   \return policy of button layouting.
153 */
154 int QtxDialog::Area::policy() const
155 {
156         return myPolicy;
157 }
158
159 /*!
160   Changes policy of button layouting.
161   \param p - new policy
162 */
163 void QtxDialog::Area::setPolicy( const int p )
164 {
165         if ( myPolicy == p )
166                 return;
167
168         myPolicy = p;
169         layoutButtons();
170 }
171
172 /*!
173   \return true if border enabled
174 */
175 bool QtxDialog::Area::isBorderEnabled() const
176 {
177         return myLine && myBorder;
178 }
179
180 /*!
181   Enables/disable separator between main frame and button frame
182   \param on - new state
183 */
184 void QtxDialog::Area::setBorderEnabled( const bool on )
185 {
186         if ( !myLine || myBorder == on )
187                 return;
188
189         myBorder = on;
190         updateBorder();
191 }
192
193 /*!
194   Sets label as separator between main frame and button frame
195   \param line - new separator
196 */
197 void QtxDialog::Area::setBorderWidget( QLabel* line )
198 {
199         if ( myLine == line )
200                 return;
201
202         delete myLine;
203         myLine = line;
204         updateBorder();
205 }
206
207 /*!
208   \return const reference to list of buttons
209 */
210 const QPtrList<QButton>& QtxDialog::Area::buttons() const
211 {
212         return myButtons;
213 }
214
215 /*!
216   Updates visibility of border
217 */
218 void QtxDialog::Area::updateBorder()
219 {
220         if ( !myLine )
221                 return;
222
223         bool isVis = isVisibleTo( parentWidget() );
224 #if QT_VER >= 3    
225         if ( isVis )
226 #else
227         if ( isVis && myBorder )
228 #endif
229                 myLine->show();
230         else
231                 myLine->hide();
232
233         myLine->setLineWidth( myBorder ? 1 : 0 );
234 }
235
236 /*!
237   Installs buttons into layout
238 */
239 void QtxDialog::Area::layoutButtons()
240 {
241         int aPolicy = policy();
242
243         QMap<QButton*, int> buttonId;
244         for ( QPtrListIterator<QButton> it1( myButtons ); it1.current(); ++it1 )
245                 buttonId.insert( it1.current(), 0 );
246
247         QPtrList<QButton> src;
248         for ( ButtonMap::Iterator mit = myDlg->myButton.begin();
249                   mit != myDlg->myButton.end(); ++mit )
250         {
251                 if ( buttonId.contains( mit.data() ) )
252                 {
253                         buttonId[mit.data()] = mit.key();
254                         if ( mit.key() >= 0 )
255                                 src.append( mit.data() );
256                 }
257         }
258
259         for ( QPtrListIterator<QButton> it2( myButtons ); it2.current(); ++it2 )
260                 if ( buttonId[it2.current()] < 0 )
261                         src.append( it2.current() );
262
263         QPtrList<QButton> left, right, center, other;
264         for ( QPtrListIterator<QButton> it( src ); it.current(); ++it )
265         {
266                 if ( !it.current()->isVisibleTo( this ) )
267                         continue;
268
269                 int aPosition = myDlg->buttonPosition( it.current() );
270                 if ( aPosition == -1 )
271                         continue;
272
273                 if ( aPolicy != QtxDialog::Position )
274                         other.append( it.current() );
275                 else if ( aPosition == QtxDialog::Left )
276                         left.append( it.current() );
277                 else if ( aPosition == QtxDialog::Right )
278                         right.append( it.current() );
279                 else if ( aPosition == QtxDialog::Center )
280                         center.append( it.current() );
281         }
282
283   delete layout();
284
285         QBoxLayout* buttonLayout = 0;
286         if ( myOrientation == Qt::Vertical )
287                 buttonLayout = new QVBoxLayout( this, 0, 5 );
288         else
289                 buttonLayout = new QHBoxLayout( this, 0, 5 );
290
291         if ( !buttonLayout )
292                 return;
293
294         if ( aPolicy == QtxDialog::Position )
295         {
296                 for ( QPtrListIterator<QButton> lit( left ); lit.current(); ++lit )
297                         buttonLayout->addWidget( lit.current() );
298                 buttonLayout->addStretch( 1 );
299                 for ( QPtrListIterator<QButton> cit( center ); cit.current(); ++cit )
300                         buttonLayout->addWidget( cit.current() );
301                 buttonLayout->addStretch( 1 );
302                 for ( QPtrListIterator<QButton> rit( right ); rit.current(); ++rit )
303                         buttonLayout->addWidget( rit.current() );
304         }
305         else
306         {
307                 for ( QPtrListIterator<QButton> oit( other ); oit.current(); ++oit )
308                 {
309                         buttonLayout->addWidget( oit.current() );
310                         if ( aPolicy == QtxDialog::Uniform && !oit.atLast() )
311                                 buttonLayout->addStretch( 1 );
312                 }
313         }
314
315   QWidgetList wids;
316   if ( layout() )
317   {
318     for ( QLayoutIterator it = layout()->iterator(); it.current(); ++it )
319     {
320       if ( !it.current()->widget() )
321         continue;
322
323       if ( QApplication::reverseLayout() )
324         wids.prepend( it.current()->widget() );
325       else
326         wids.append( it.current()->widget() );
327     }
328   }
329   Qtx::setTabOrder( wids );
330 }
331
332
333 /*!
334   \class QtxDialog::Border
335
336   Special label used as separator between main frame and button frame
337 */
338 class QtxDialog::Border : public QLabel
339 {
340 public:
341         Border( QWidget* = 0 );
342         virtual ~Border();
343
344         virtual void setLineWidth( int );
345
346         virtual QSize sizeHint() const;
347         virtual QSize minimumSizeHint() const;
348 };
349
350 /*!
351   Constructor
352 */
353 QtxDialog::Border::Border( QWidget* parent )
354 : QLabel( parent )
355 {
356     setAlignment( Qt::AlignCenter );
357 }
358
359 /*!
360   Destructor
361 */
362 QtxDialog::Border::~Border()
363 {
364 }
365
366 /*!
367   Set line width of separator
368   \param lw - new line width
369 */
370 void QtxDialog::Border::setLineWidth( int lw )
371 {
372   bool isOn = lineWidth() > 0;
373
374   QLabel::setLineWidth( lw );
375     
376   if ( isOn != ( lineWidth() > 0 ) )
377     updateGeometry();
378 }
379
380 /*!
381   \return the recommended size for the widget
382 */
383 QSize QtxDialog::Border::sizeHint() const
384 {
385   QSize sz( 5, 5 );
386
387 #if QT_VER >= 3    
388   if ( lineWidth() > 0 )
389         {
390     if ( frameShape() == VLine )
391       sz += QSize( 5 + lineWidth(), 0 );
392                 else if ( frameShape() == HLine )
393       sz += QSize( 0, 5 + lineWidth() );
394         }
395 #endif
396
397   return sz;
398 }
399
400 /*!
401   \return the recommended minimum size for the widget
402 */
403 QSize QtxDialog::Border::minimumSizeHint() const
404 {
405         return sizeHint();
406 }
407
408 /*!
409   Constructor
410   Construct a dialog with specified parent and name.
411   \param modal define modal status of dialog (default non modal dialog created).
412   \param allowResize - if it is true then dialog can be resize by user (default non resizable dialog created).
413   \param Button flags specified control buttons for dialog (default buttons is OK, Cancel and Help).
414   \param Widget flags used as in any widget.
415 */
416 QtxDialog::QtxDialog( QWidget* parent, const char* name,
417                                           bool modal, bool allowResize, const int f, WFlags wf )
418 : QDialog( parent, name, modal,
419 #ifdef WIN32
420            wf | WStyle_Customize | WStyle_Title | WStyle_SysMenu |
421            ( allowResize ? WStyle_NormalBorder : WStyle_NoBorderEx ) ),
422 #else
423            wf | WStyle_NormalBorder | WStyle_Customize | WStyle_Title | WStyle_SysMenu ),
424 #endif
425 mySender( 0 ),
426 myAlignment( 0 ),
427 myInited( false ),
428 myDialogFlags( Accept | SetFocus )
429 {
430         QVBoxLayout* base = new QVBoxLayout( this, 5, 0 );
431         QtxGroupBox* main = new QtxGroupBox( 1, Qt::Horizontal, "", this );
432         main->setFrameStyle( QFrame::NoFrame );
433         main->setInsideMargin( 0 );
434         main->setInsideSpacing( 0 );
435         base->addWidget( main );
436
437         Area* topArea = new Area( Qt::Horizontal, this, main );
438         QLabel* topLine = new Border( main );
439         QtxGroupBox* midGroup = new QtxGroupBox( 1, Qt::Vertical, "", main );
440         QLabel* botLine = new Border( main );
441         Area* botArea = new Area( Qt::Horizontal, this, main );
442
443         midGroup->setFrameStyle( QFrame::NoFrame );
444         midGroup->setInsideMargin( 0 );
445         midGroup->setInsideSpacing( 0 );
446
447         Area* leftArea = new Area( Qt::Vertical, this, midGroup );
448         QLabel* leftLine = new Border( midGroup );
449         myMainFrame = new QFrame( midGroup );
450         QLabel* rightLine = new Border( midGroup );
451         Area* rightArea = new Area( Qt::Vertical, this, midGroup );
452
453         myMainFrame->setSizePolicy( QSizePolicy( QSizePolicy::Expanding,
454                                                                                                 QSizePolicy::Expanding ) );
455
456         topLine->setFrameStyle( QFrame::Sunken | QFrame::HLine );
457         botLine->setFrameStyle( QFrame::Sunken | QFrame::HLine );
458         leftLine->setFrameStyle( QFrame::Sunken | QFrame::VLine );
459         rightLine->setFrameStyle( QFrame::Sunken | QFrame::VLine );
460         topArea->setBorderWidget( topLine );
461         botArea->setBorderWidget( botLine );
462         leftArea->setBorderWidget( leftLine );
463         rightArea->setBorderWidget( rightLine );
464
465         myArea.insert( TopArea,    topArea );
466         myArea.insert( BottomArea, botArea );
467         myArea.insert( LeftArea,   leftArea );
468         myArea.insert( RightArea,  rightArea );
469
470         for ( AreaMap::Iterator itr = myArea.begin(); itr != myArea.end(); ++ itr )
471                 itr.data()->setBorderEnabled( false );
472
473         myButton.insert( OK,     new QPushButton( tr( "&OK" ),     this ) );
474         myButton.insert( Cancel, new QPushButton( tr( "&Cancel" ), this ) );
475         myButton.insert( Close,  new QPushButton( tr( "C&lose" ),  this ) );
476         myButton.insert( Help,   new QPushButton( tr( "&Help" ),   this ) );
477         myButton.insert( Apply,  new QPushButton( tr( "&Apply" ),  this ) );
478         myButton.insert( Yes,    new QPushButton( tr( "&Yes" ),    this ) );
479         myButton.insert( No,     new QPushButton( tr( "&No" ),     this ) );
480
481         for ( ButtonMap::Iterator it = myButton.begin(); it != myButton.end(); ++it )
482         {
483                 ((QPushButton*)it.data())->setAutoDefault( false );
484 #if QT_VER >= 3
485                 connect( it.data(), SIGNAL( destroyed( QObject* ) ), this, SLOT( onDestroyed( QObject* ) ) );
486 #endif
487         }
488
489         setButtonPosition( Left,   OK | Cancel | Apply );
490         setButtonPosition( Center, Yes | No | Close );
491         setButtonPosition( Right,  Help );
492         setButtonPlace( BottomArea, All );
493
494         connect( myButton[Apply],  SIGNAL( clicked() ), this, SIGNAL( dlgApply() ) );
495         connect( myButton[Help],   SIGNAL( clicked() ), this, SIGNAL( dlgHelp() ) );
496
497         connect( myButton[OK],     SIGNAL( clicked() ), this, SLOT( onAccept() ) );
498         connect( myButton[Cancel], SIGNAL( clicked() ), this, SLOT( onReject() ) );
499         connect( myButton[Yes],    SIGNAL( clicked() ), this, SLOT( onAccept() ) );
500         connect( myButton[No],     SIGNAL( clicked() ), this, SLOT( onReject() ) );
501         connect( myButton[Close],  SIGNAL( clicked() ), this, SLOT( onReject() ) );
502
503         QPixmap icon;
504         if ( qApp && qApp->mainWidget() && qApp->mainWidget()->icon() )
505                 setIcon( *qApp->mainWidget()->icon() );
506
507         myButtonFlags = f;
508
509 #ifndef WIN32
510         if ( !allowResize )
511                 setMaximumSize( minimumSize() );
512 #endif
513
514         update();
515 }
516
517 /*!
518         Name: ~QtxDialog [public]
519         Desc: Destructor
520 */
521
522 QtxDialog::~QtxDialog()
523 {
524 }
525
526 /*!
527         Name: setButtonFlags [public]
528         Desc: Allow to set specified control button(s) into dialog.
529 */
530
531 void QtxDialog::setButtonFlags( const int f )
532 {
533         int old = myButtonFlags;
534         myButtonFlags = myButtonFlags | f;
535         if ( old != myButtonFlags )
536                 update();
537 }
538
539 /*!
540         Name: clearButtonFlags [public]
541         Desc: Allow to unset specified control button(s) from dialog.
542 */
543
544 void QtxDialog::clearButtonFlags( const int f )
545 {
546         int old = myButtonFlags;
547         myButtonFlags = myButtonFlags & ~f;
548         if ( old != myButtonFlags )
549                 update();
550 }
551
552 /*!
553         Name: testButtonFlags [public]
554         Desc: Return true if specified control button is used in dialog.
555 */
556
557 bool QtxDialog::testButtonFlags( const int f ) const
558 {
559     return ( myButtonFlags & f ) == f;
560 }
561
562 /*!
563         Name: setDialogFlags [public]
564         Desc: Allow to set the dialog flags.
565
566                   Following flags can be used:
567                         Accept    - Allow to control dialog accepting. See also acceptData().
568                         Reject    - Allow to control dialog rejecting. See also rejectData().
569                         AlignOnce - Allow to align dialog only when it first time shown.
570                         SetFocus  - Allow to set focus on dialog when it shown. User can use
571                   setFocusProxy() and specify own initial focus widget.
572 */
573
574 void QtxDialog::setDialogFlags( const int f )
575 {
576         myDialogFlags = myDialogFlags | f;
577 }
578
579 /*!
580         Name: clearDialogFlags [public]
581         Desc: Allow to clear the dialog flags. See also setDialogFlags().
582 */
583
584 void QtxDialog::clearDialogFlags( const int f )
585 {
586         myDialogFlags = myDialogFlags & ~f;
587 }
588
589 /*!
590         Name: testDialogFlags [public]
591         Desc: Returns true if specified dialog flag is setted (see setDialogFlags()).
592 */
593
594 bool QtxDialog::testDialogFlags( const int f ) const
595 {
596     return ( myDialogFlags & f ) == f;
597 }
598
599 /*!
600         Name: mainFrame [public]
601         Desc: Returns main frame of dialog. Main frame should contains all
602           elements of dialog except control buttons.
603 */
604
605 QFrame* QtxDialog::mainFrame() const
606 {
607     return myMainFrame;
608 }
609
610 /*!
611         Name: buttonPosition [public]
612         Desc: Returns position of specified button.
613 */
614
615 int QtxDialog::buttonPosition( const int id ) const
616 {
617         int pos = -1;
618         if ( myPosition.contains( id ) )
619                 pos = myPosition[id];
620         return pos;
621 }
622
623 /*!
624         Name: setButtonPosition [public]
625         Desc: Sets the position for specified button(s). Following positions
626                   may be used: Left, Right, Center, Top, Bottom.
627 */
628
629 void QtxDialog::setButtonPosition( const int pos, const int id )
630 {
631         ButtonMap map = buttons( id );
632
633         QMap<QObject*, int> changed;
634         for ( ButtonMap::Iterator it = map.begin(); it != map.end(); ++it )
635         {
636                 if ( myPosition[it.key()] == pos )
637                         continue;
638       
639                 myPosition[it.key()] = pos;
640                 if ( button( it.key() ) )
641                         changed.insert( button( it.key() )->parent(), 0 );
642     }
643
644         for ( AreaMap::Iterator itr = myArea.begin(); itr != myArea.end(); ++itr )
645                 if ( changed.contains( itr.data() ) )
646                         itr.data()->layoutButtons();
647 }
648
649 /*!
650         Name: setPlacePosition [public]
651         Desc: Sets button position for all buttons in given place.
652 */
653
654 void QtxDialog::setPlacePosition( const int pos, const int area )
655 {
656         if ( !myArea.contains( area ) )
657                 return;
658
659         Area* anArea = myArea[area];
660
661         bool changed = false;
662         for ( ButtonMap::Iterator it = myButton.begin(); it != myButton.end(); ++it )
663         {
664                 if ( !anArea->contains( it.data() ) )
665                         continue;
666
667                 changed = changed &&  myPosition[it.key()] != pos;
668
669                 myPosition[it.key()] = pos;
670     }
671
672         if ( changed )
673                 anArea->layoutButtons();
674 }
675
676 /*!
677         Name: placePolicy [public]
678         Desc: Returns policy of button layouting for specified place.
679
680                   Following place may be used:
681                         TopArea    - Horizontal area in the top side of dialog.
682                         BottomArea - Horizontal area in the bottom side of dialog.
683                         LeftArea   - Vertical area in the left side of dialog.
684                         RightArea  - Vertical area in the right side of dialog.
685
686                   Following policy may be used:
687                     Position - Buttons placed according their position.
688                         Expand   - Buttons fills all available space.
689                         Uniform  - Buttons uniformly placed in area.
690 */
691
692 int QtxDialog::placePolicy( const int area ) const
693 {
694         int res = -1;
695         if ( myArea.contains( area ) )
696                 res = myArea[area]->policy();
697         return res;
698 }
699
700 /*!
701         Name: setPlacePolicy [public]
702         Desc: Sets the policy of button layouting for specified place.
703                   See also placePolicy().
704 */
705
706 void QtxDialog::setPlacePolicy( const int policy, const int area )
707 {
708         if ( area < 0 )
709                 for ( AreaMap::Iterator itr = myArea.begin(); itr != myArea.end(); ++itr )
710                         itr.data()->setPolicy( policy );
711         else if ( myArea.contains( area ) )
712                 myArea[area]->setPolicy( policy );
713 }
714
715 /*!
716         Name: setButtonPlace [public]
717         Desc: Move given button(s) into specified place.
718 */
719
720 void QtxDialog::setButtonPlace( const int area, const int ids )
721 {
722         if ( !myArea.contains( area ) )
723                 return;
724
725         Area* anArea = myArea[area];
726
727         ButtonMap map = buttons( ids );
728
729         QMap<Area*, int> areaMap;
730         for ( AreaMap::ConstIterator aIt = myArea.begin(); aIt != myArea.end(); ++aIt )
731                 areaMap.insert( aIt.data(), 0 );
732
733         for ( ButtonMap::Iterator it = map.begin(); it != map.end(); ++it )
734         {
735                 Area* old = (Area*)it.data()->parent();
736                 if ( old == anArea )
737                         continue;
738
739                 if ( areaMap.contains( old ) )
740                         old->removeButton( it.data() );
741                 anArea->insertButton( it.data() );
742     }
743 }
744
745 /*!
746         Name: isBorderEnabled [public]
747         Desc: Returns true if border is shown for specified button area.
748 */
749
750 bool QtxDialog::isBorderEnabled( const int area ) const
751 {
752         bool res = false;
753         if ( myArea.contains( area ) )
754                 res  = myArea[area]->isBorderEnabled();
755         return res;
756 }
757
758 /*!
759         Name: setBorderEnabled [public]
760         Desc: Show/hide border for specified button area. Border are
761               line which separate main frame and control buttons.
762 */
763
764 void QtxDialog::setBorderEnabled( const bool on, const int area )
765 {
766         if ( !myArea.contains( area ) )
767                 return;
768
769         if ( myArea[area]->isBorderEnabled() == on )
770                 return;
771
772         myArea[area]->setBorderEnabled( on );
773
774         if ( isVisible() )
775         {
776                 QApplication::sendPostedEvents();
777                 adjustSize();
778         }
779 }
780
781 /*!
782         Name: isButtonEnabled [public]
783         Desc: Returns true if all specified button(s) is enabled.
784 */
785
786 bool QtxDialog::isButtonEnabled( const int f ) const
787 {
788         ButtonMap map = buttons( f );
789         bool result = !map.isEmpty();
790         for ( ButtonMap::Iterator it = map.begin(); it != map.end(); ++it )
791                 result = result && it.data()->isEnabled();
792         return result;
793 }
794
795 /*!
796         Name: setButtonEnabled [public]
797         Desc: Enable/disable specified button(s).
798 */
799
800 void QtxDialog::setButtonEnabled( const bool on, const int ids )
801 {
802         ButtonMap map = buttons( ids );
803         for ( ButtonMap::Iterator it = map.begin(); it != map.end(); ++it )
804                 it.data()->setEnabled( on );
805 }
806
807 /*!
808         Name: hasButtonFocus [public]
809         Desc: Retruns true if specified button has keyboard focus.
810 */
811
812 bool QtxDialog::hasButtonFocus( const int id ) const
813 {
814         bool res = false;
815         QButton* pb = button( id );
816         if ( pb )
817         res = pb->hasFocus();
818         return res;
819 }
820
821 /*!
822         Name: setButtonFocus [public]
823         Desc: Sets the keyboard focus on specified button.
824 */
825
826 void QtxDialog::setButtonFocus( const int id )
827 {
828         QButton* pb = button( id );
829         if ( pb )
830             pb->setFocus();
831 }
832
833 /*!
834         Name: buttonText [public]
835         Desc: Return text of specified button.
836 */
837
838 QString QtxDialog::buttonText( const int id )
839 {
840         QString retval;
841         QButton* but = button( id );
842         if ( but )
843                 retval = but->text();
844         return retval;
845 }
846
847 /*!
848         Name: setButtonText [public]
849         Desc: Sets text to specified button.
850 */
851
852 void QtxDialog::setButtonText( const int id, const QString& text )
853 {
854         QButton* but = button( id );
855         if ( but && but->text() != text )
856         {
857                 but->setText( text );
858                 adjustButtons();
859         }
860 }
861
862 /*!
863         Name: setAlignment [public]
864         Desc: Sets alignment policy. Returns the previous alignment.
865                   Use the function before the first show of the dialog.
866                   If dialog flag AlignOnce is setted then align will performed
867                   only one time otherwise dialog will be aligned every time
868                   when it shown. Dialog will be aligned relative to it parent.
869
870                   Following align flags may be used:
871                         Qtx::AlignAuto      - Align to center of desktop (default).
872                         Qtx::AlignLeft      - Align left side of dialog to left side of parent.
873                         Qtx::AlignRight     - Align right side of dialog to right side of parent.
874                         Qtx::AlignTop       - Align top side of dialog to top side of parent.
875                         Qtx::AlignBottom    - Align bottom side of dialog to bottom side of parent.
876                         Qtx::AlignHCenter   - Align dialog to center of parent in horizontal dimension.
877                         Qtx::AlignVCenter   - Align dialog to center of parent in vertical dimension.
878                         Qtx::AlignCenter    - Align dialog to center of parent in both dimensions.
879                         Qtx::AlignOutLeft   - Align right side of dialog to left side of parent.
880                         Qtx::AlignOutRight  - Align left side of dialog to right side of parent.
881                         Qtx::AlignOutTop    - Align bottom side of dialog to top side of parent.
882                         Qtx::AlignOutBottom - Align top side of dialog to bottom side of parent.
883 */
884
885 uint QtxDialog::setAlignment( uint align )
886 {
887   uint oldAlign = myAlignment;
888   myAlignment = align;
889   return oldAlign;
890 }
891
892 /*!
893         Name: update [virtual public slot]
894         Desc: Updates dialog, show selected buttons and hide unselected.
895 */
896
897 void QtxDialog::update()
898 {
899         for ( ButtonMap::Iterator it = myButton.begin(); it != myButton.end(); ++it )
900                 if ( it.key() >= 0 )
901                         testButtonFlags( it.key() ) ? it.data()->show() : it.data()->hide();
902
903         for ( AreaMap::Iterator itr = myArea.begin(); itr != myArea.end(); ++itr )
904                 itr.data()->layoutButtons();
905
906         adjustButtons();
907
908         QDialog::update();
909 }
910
911 /*!
912         Name: show [virtual public]
913         Desc: Show dialog, set keyboard focus on dialog.
914 */
915
916 void QtxDialog::show()
917 {
918         QDialog::show();
919
920         if ( testDialogFlags( SetFocus ) )
921           setFocus();
922
923         myInited = true;
924 }
925
926 /*!
927         Name: hide [virtual public]
928         Desc: Hides dialog, processed all posted events.
929 */
930
931 void QtxDialog::hide()
932 {
933         QDialog::hide();
934         qApp->processEvents();
935 }
936
937 /*!
938         Name: userButton [public]
939         Desc: Return user dialog button using specified identificator.
940 */
941
942 QButton* QtxDialog::userButton( const int id ) const
943 {
944         QButton* b = 0;
945         if ( id < -1 && myButton.contains( id ) )
946                 b = myButton[id];
947     return b;
948 }
949
950 /*!
951         Name: userButtonIds [public]
952         Desc: Return list of user dialog button identificators.
953 */
954
955 QValueList<int> QtxDialog::userButtonIds() const
956 {
957         QValueList<int> retlist;
958         for ( ButtonMap::ConstIterator it = myButton.begin(); it != myButton.end(); ++it )
959                 if ( it.key() < 0 )
960                         retlist.append( it.key() );
961         return retlist;
962 }
963
964 /*!
965         Name: insertButton [public]
966         Desc: Add new user dialog button. Function return identificator of
967                   newly added button in successfull case otherwise -1 will be returned.
968 */
969
970 int QtxDialog::insertButton( const QString& text, const int area )
971 {
972         if ( !myArea.contains( area ) )
973                 return -1;
974
975         int id = -2;
976         while ( myButton.contains( id ) )
977                 id--;
978
979         Area* anArea = myArea[area];
980         QButton* b = createButton( this );
981         if ( b )
982         {
983                 b->setText( text );
984                 myButton.insert( id, b );
985                 myPosition.insert( id, Left );
986
987                 connect( b, SIGNAL( clicked() ), this, SLOT( onButton() ) );
988 #if QT_VER >= 3
989                 connect( b, SIGNAL( destroyed( QObject* ) ), this, SLOT( onDestroyed( QObject* ) ) );
990 #endif
991
992                 anArea->insertButton( b );
993                 update();
994         }
995         else
996                 id = -1;
997
998         return id;
999 }
1000
1001 /*!
1002         Name: removeButton [public]
1003         Desc: Remove user dialog button with specified identificator. If
1004                   identificator equal -1 then method will remove all user dialog buttons.
1005 */
1006
1007 void QtxDialog::removeButton( const int id )
1008 {
1009         if ( id >= 0 )
1010                 return;
1011
1012         ButtonMap map;
1013         if ( id == -1 )
1014         {
1015                 for ( ButtonMap::Iterator it = myButton.begin(); it != myButton.end(); ++it )
1016                 {
1017                         if ( it.key() < 0 )
1018                                 map.insert( it.key(), it.data() );
1019                 }
1020         }
1021         else if ( myButton.contains( id ) )
1022                 map.insert( id, myButton[id] );
1023
1024         for ( ButtonMap::Iterator itr = map.begin(); itr != map.end(); ++itr )
1025         {
1026                 for ( AreaMap::Iterator it = myArea.begin(); it != myArea.end(); ++it )
1027                         it.data()->removeButton( itr.data() );
1028
1029                 myButton.remove( itr.key() );
1030                 myPosition.remove( itr.key() );
1031
1032                 delete itr.data();
1033         }
1034     update();
1035 }
1036
1037 /*!
1038         Name: setUnits [static public]
1039         Desc: Sets specified measure units in given label. Measure units close
1040                   in braces. If measure units not exist then they will be added.
1041                   For example:
1042                         1. Label contains text 'Radius'.
1043                            setUnits( aLabel, "mm" )    => aLabel contains 'Radius (mm)'
1044                setUnits( aLabel, "cm" )    => aLabel contains 'Radius (cm)'
1045             2. Label "aLabel" contains text 'Radius ():'.
1046                setUnits( aLabel, "mm" )    => aLabel contains 'Radius (mm):'
1047                setUnits( aLabel, "cm" )    => aLabel contains 'Radius (cm):'
1048 */
1049
1050 void QtxDialog::setUnits( QLabel* aLabel, const QString& aUnits )
1051 {
1052         QString label = aLabel->text();
1053         int begin;
1054         int end = label.findRev( ')' );
1055
1056         QString startLabel = label;
1057         QString finalLabel;
1058
1059         if ( end != -1 )
1060         {
1061                 begin = label.left( end ).findRev( '(' );
1062                 if ( begin != -1 )
1063                 {
1064                         startLabel = label.mid( 0, begin );
1065                         finalLabel = label.mid( end + 1 );
1066                 }
1067         }
1068         else
1069         {
1070                 startLabel = startLabel.stripWhiteSpace();
1071                 if ( startLabel.at( startLabel.length() - 1 ) == ':' )
1072                 {
1073                         finalLabel = startLabel.mid( startLabel.length() - 1 );
1074                         startLabel = startLabel.mid( 0, startLabel.length() - 1 );
1075                 }
1076         }
1077         if ( aUnits.length() )
1078                 label = startLabel.stripWhiteSpace() +
1079                 " (" + aUnits + ") " + finalLabel.stripWhiteSpace();
1080         else
1081                 label = startLabel.stripWhiteSpace() +
1082                 " " + finalLabel.stripWhiteSpace();
1083         aLabel->setText( label );
1084 }
1085
1086 /*!
1087         Name: acceptData [virtual protected]
1088         Desc: If returns true dialog will be accepted and closed. This method
1089               called if dialog flag Accept is setted.
1090 */
1091
1092 bool QtxDialog::acceptData() const
1093 {
1094   return true;
1095 }
1096
1097 /*!
1098         Name: rejectData [virtual protected]
1099         Desc: If returns true dialog will be rejected and closed. This method
1100               called if dialog flag Reject is setted.
1101 */
1102
1103 bool QtxDialog::rejectData() const
1104 {
1105         return true;
1106 }
1107
1108 /*!
1109         Name: createButton [virtual protected]
1110         Desc: Create new user button. Invoked from method "insertButton".
1111 */
1112
1113 QButton* QtxDialog::createButton( QWidget* parent )
1114 {
1115         QPushButton* pb = new QPushButton( parent );
1116         pb->setAutoDefault( false );
1117         return pb;
1118 }
1119
1120 /*!
1121         Name: button [protected]
1122         Desc: Return pointer on control button specified by identifier.
1123                   If identifier is wrong then null pointer will returned.
1124 */
1125
1126 QButton* QtxDialog::button( const int f ) const
1127 {
1128         QButton* retval = 0;
1129         if ( myButton.contains( f ) )
1130                 retval = myButton[f];
1131         return retval;
1132 }
1133
1134 /*!
1135         Name: buttons [protected]
1136         Desc: Return map with control dialog buttons accordance to given button flags.
1137 */
1138
1139 QtxDialog::ButtonMap QtxDialog::buttons( const int f ) const
1140 {
1141         ButtonMap retmap;
1142         if ( f < -1 )
1143         {
1144                 if ( myButton.contains( f ) )
1145                         retmap.insert( f, myButton[f] );
1146         }
1147         else
1148         {
1149                 for ( ButtonMap::ConstIterator it = myButton.begin(); it != myButton.end(); ++it )
1150                         if ( f == -1 || ( it.key() >= 0 && f & it.key() ) )
1151                                 retmap.insert( it.key(), it.data() );
1152         }
1153
1154         return retmap;
1155 }
1156
1157 /*!
1158         Name: buttonId [protected]
1159         Desc: Return identifier of specified button.
1160 */
1161
1162 int QtxDialog::buttonId( const QButton* b ) const
1163 {
1164         int id = -1;
1165         for ( ButtonMap::ConstIterator it = myButton.begin(); it != myButton.end() && id == -1; ++it )
1166                 if ( it.data() == b )
1167                         id = it.key();
1168         return id;
1169 }
1170
1171 /*!
1172         Name: buttonPosition
1173         Desc: Returns position of specified button. [protected]
1174 */
1175
1176 int QtxDialog::buttonPosition( QButton* b ) const
1177 {
1178         return buttonPosition( buttonId( b ) );
1179 }
1180
1181 /*!
1182         Name: showEvent [virtual protected]
1183         Desc: Aligns this dialog according the parent widget and alignment
1184               policy before the show.
1185 */
1186
1187 void QtxDialog::showEvent( QShowEvent* e )
1188 {
1189         if ( !testDialogFlags( AlignOnce ) || !myInited )
1190                 Qtx::alignWidget( this, parentWidget(), myAlignment );
1191         QDialog::showEvent( e );
1192 }
1193
1194 /*!
1195         Name: hideEvent [virtual protected]
1196         Desc: Process all existing events when dialog is closed.
1197 */
1198
1199 void QtxDialog::hideEvent( QHideEvent* e )
1200 {
1201         qApp->processEvents();
1202         QDialog::hideEvent( e );
1203 }
1204
1205 /*!
1206         Name: childEvent [virtual protected]
1207         Desc: Setting up layout when size grip is added.
1208 */
1209
1210 void QtxDialog::childEvent( QChildEvent* e )
1211 {
1212         QDialog::childEvent( e );
1213         if ( layout() && e->inserted() && e->child()->inherits( "QSizeGrip" ) )
1214         {
1215                 layout()->setMargin( 12 );
1216 #if QT_VER >= 3
1217                 connect( e->child(), SIGNAL( destroyed() ), this, SLOT( onSizeGripDestroyed() ) );
1218 #endif
1219         }
1220 }
1221
1222 /*!
1223         Name: keyPressEvent [virtual protected]
1224         Desc: Calls reject() if key Escape is pressed.
1225               Calls accept() if key "Ctrl+Enter" is pressed.
1226                   Process key "F1" and emit signal dlgHelp().
1227                   Transfer key "Ctrl+(Shift+)Tab" press event to Tab Widget.
1228 */
1229
1230 void QtxDialog::keyPressEvent( QKeyEvent* e )
1231 {
1232         QDialog::keyPressEvent( e );
1233         if ( e->isAccepted() )
1234             return;
1235
1236         if ( ( e->state() == 0 ) && ( e->key() == Key_Escape ) )
1237                 reject();
1238
1239         if ( ( e->state() == ControlButton ) && ( e->key() == Key_Return ) )
1240         {
1241                 if ( testButtonFlags( OK ) || testButtonFlags( Yes ) )
1242                         accept();
1243                 else if ( testButtonFlags( Apply ) && isButtonEnabled( Apply ) )
1244                         emit dlgApply();
1245                 e->accept();
1246         }
1247
1248         if ( e->key() == Key_F1 && testButtonFlags( Help ) && isButtonEnabled( Help ) )
1249         {
1250                 e->accept();
1251                 emit dlgHelp();
1252         }
1253
1254         if ( ( e->key() == Key_Tab ) && ( e->state() & ControlButton ) )
1255         {
1256                 QObject* tab = child( 0, "QTabWidget" );
1257                 if ( tab )
1258                         tab->event( e );
1259         }
1260 }
1261
1262 /*!
1263         Name: closeEvent [virtual protected]
1264         Desc: Reject the dialog.
1265 */
1266
1267 void QtxDialog::closeEvent( QCloseEvent* )
1268 {
1269         reject();
1270 }
1271
1272 /*!
1273         Name: accept [virtual protected slot]
1274         Desc: Invoke function acceptData() if it needed and if acceptData() return
1275                   false does nothing. Otherwise hides the dialog and sets the result code
1276                   to Accepted. Emit signal according to the pressed control button.
1277 */
1278
1279 void QtxDialog::accept()
1280 {
1281         if ( !mySender )
1282         {
1283                 if ( testButtonFlags( OK ) )
1284                         mySender = button( OK );
1285                 else if ( testButtonFlags( Yes ) )
1286                         mySender = button( Yes );
1287                 else
1288                         mySender = button( Close );
1289         }
1290
1291   if ( !mySender || !mySender->isWidgetType() ||
1292        !((QWidget*)mySender)->isEnabled() )
1293                 return;
1294
1295         if ( testDialogFlags( Accept ) && !acceptData() )
1296                 return;
1297
1298         QDialog::accept();
1299
1300         emitSignal();
1301 }
1302
1303 /*!
1304         Name: reject [virtual protected slot]
1305         Desc: Invoke function rejectData() if it needed and if rejectData() return
1306                   false does nothing. Otherwise hides the dialog and sets the result code
1307                   to Rejected. Emit signal according to the pressed control button. (If
1308                   dialog was closed by key Escape or by close event emit signal dlgCancel(),
1309                   or dlgClose(), or dlgNo().
1310 */
1311
1312 void QtxDialog::reject()
1313 {
1314         if ( testDialogFlags( Reject ) && !rejectData() )
1315                 return;
1316
1317         if ( !mySender )
1318         {
1319                 if ( testButtonFlags( Cancel ) )
1320                         mySender = button( Cancel );
1321                 else if ( testButtonFlags( No ) )
1322                         mySender = button( No );
1323                 else
1324                         mySender = button( Close );
1325         }
1326
1327     if ( !mySender || !mySender->isWidgetType() ||
1328          !((QWidget*)mySender)->isEnabled() )
1329         return;
1330
1331         QDialog::reject();
1332
1333         emitSignal();
1334 }
1335
1336 /*!
1337         Name: reject [private]
1338         Desc: Emit signal appropriate to control button.
1339 */
1340
1341 void QtxDialog::emitSignal()
1342 {
1343         qApp->processEvents();
1344         QApplication::syncX();
1345
1346         int id = buttonId( (QButton*)mySender );
1347         mySender = 0;
1348
1349         switch ( id )
1350         {
1351         case OK:
1352                 emit dlgOk();
1353                 break;
1354         case Cancel:
1355                 emit dlgCancel();
1356                 break;
1357         case Close:
1358                 emit dlgClose();
1359                 break;
1360         case Yes:
1361                 emit dlgYes();
1362                 break;
1363         case No:
1364                 emit dlgNo();
1365                 break;
1366         }
1367 }
1368
1369 /*!
1370         Name: onAccept [private slot]
1371         Desc: Process signals "clicked()" from control buttons "OK", "Yes". Invoke accept().
1372 */
1373
1374 void QtxDialog::onAccept()
1375 {
1376     const QObject* obj = sender();
1377     mySender = obj;
1378     accept();
1379 }
1380
1381 /*!
1382         Name: onReject [private slot]
1383         Desc: Process signals "clicked()" from control buttons "Cancel", "No", "Close".
1384                   Invoke reject().
1385 */
1386
1387 void QtxDialog::onReject()
1388 {
1389   const QObject* obj = sender();
1390   mySender = obj;
1391   reject();
1392 }
1393
1394 /*!
1395         Name: onButton [private slot]
1396         Desc: Receive signal "clicked()" from user buttons and emit signal
1397                   "dlgButton( int )" with identificator of clicked user button.
1398 */
1399
1400 void QtxDialog::onButton()
1401 {
1402         int id = buttonId( (QButton*)sender() );
1403         if ( id != -1 )
1404                 emit dlgButton( id );
1405 }
1406
1407 /*!
1408         Name: onDestroyed [private slot]
1409         Desc: Remove user button if it was destroyed.
1410 */
1411
1412 void QtxDialog::onDestroyed( QObject* obj )
1413 {
1414         QButton* b = (QButton*)obj;
1415         int id = buttonId( b );
1416         if ( id == -1 )
1417                 return;
1418
1419         myButton.remove( id );
1420         myPosition.remove( id );
1421         for ( AreaMap::Iterator it = myArea.begin(); it != myArea.end(); ++it )
1422                 it.data()->removeButton( b );
1423 }
1424
1425 /*!
1426         Name: onSizeGripDestroyed [private slot]
1427         Desc: Setting up layout when size grip is destroyed.
1428 */
1429
1430 void QtxDialog::onSizeGripDestroyed()
1431 {
1432         if ( layout() )
1433                 layout()->setMargin( 5 );
1434 }
1435
1436 /*!
1437         Name: adjustButtons [private]
1438         Desc: Setting the equal with for all buttons.
1439 */
1440
1441 void QtxDialog::adjustButtons()
1442 {
1443         int minWidth = 0;
1444         for ( AreaMap::Iterator aIt = myArea.begin(); aIt != myArea.end(); ++aIt )
1445                 for ( QPtrListIterator<QButton> bIt( aIt.data()->buttons() ); bIt.current(); ++bIt )
1446                         if ( bIt.current()->isVisibleTo( this ) )
1447                                 minWidth = QMAX( minWidth, bIt.current()->sizeHint().width() );
1448
1449         for ( AreaMap::Iterator aItr = myArea.begin(); aItr != myArea.end(); ++aItr )
1450                 for ( QPtrListIterator<QButton> bItr( aItr.data()->buttons() ); bItr.current(); ++bItr )
1451                         if ( bItr.current()->isVisibleTo( this ) )
1452                                 bItr.current()->setMinimumWidth( minWidth );
1453 }