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