picking up branches/tmp/sh/qt4-port/, merging it with trunk
[duncan/yast2-qt4.git] / src / YQDialog.cc
1 /*---------------------------------------------------------------------\
2 |                                                                      |
3 |                      __   __    ____ _____ ____                      |
4 |                      \ \ / /_ _/ ___|_   _|___ \                     |
5 |                       \ V / _` \___ \ | |   __) |                    |
6 |                        | | (_| |___) || |  / __/                     |
7 |                        |_|\__,_|____/ |_| |_____|                    |
8 |                                                                      |
9 |                               core system                            |
10 |                                                        (C) SuSE GmbH |
11 \----------------------------------------------------------------------/
12
13   File:         YQDialog.cc
14
15   Author:       Stefan Hundhammer <sh@suse.de>
16
17   Textdomain    "packages-qt"
18
19 /-*/
20
21
22 #define y2log_component "qt-ui"
23 #include <ycp/y2log.h>
24 #include <qpushbutton.h>
25 #include <qframe.h>
26 #include <qmessagebox.h>
27 #include <QDesktopWidget>
28
29 #include "YQUI.h"
30 #include "YQi18n.h"
31 #include "YEvent.h"
32 #include "YQDialog.h"
33 #include "YQGenericButton.h"
34 #include "YQWizardButton.h"
35 #include "YQWizard.h"
36
37 // Include low-level X headers AFTER Qt headers:
38 // X.h pollutes the global namespace (!!!) with pretty useless #defines
39 // like "Above", "Below" etc. that clash with some Qt headers.
40 #include <X11/Xlib.h>
41
42
43 YQDialog::YQDialog( const YWidgetOpt &  opt,
44                     QWidget *           qt_parent,
45                     bool                default_size )
46     : QWidget( qt_parent,
47                default_size ? Qt::Widget : Qt::Window ) // WFlags
48     , YDialog( opt )
49 {
50     _userResized        = false;
51     _focusButton        = 0;
52     _defaultButton      = 0;
53
54     setWidgetRep( this );
55     setCaption( hasDefaultSize() ? "YaST2" : "" );
56     setFocusPolicy( Qt::StrongFocus );
57
58     if ( ! default_size )
59         setWindowModality( Qt::WindowModal );
60
61     if ( hasWarnColor() || hasInfoColor() )
62     {
63         QColor normalBackground     ( 0, 128, 0 );
64         QColor inputFieldBackground ( 0,  96, 0 );
65         QColor text = Qt::white;
66
67         if ( hasInfoColor() )
68         {
69             normalBackground = QColor ( 238, 232, 170 ); // PaleGoldenrod
70         }
71
72         QPalette warnPalette( normalBackground );
73         QColorGroup normalColors = warnPalette.normal();
74         normalColors.setColor( QColorGroup::Text, text );
75         normalColors.setColor( QColorGroup::Base, inputFieldBackground );
76         warnPalette.setNormal( normalColors );
77         setPalette( warnPalette );
78     }
79
80     _qFrame = new Q3Frame ( this );
81     bool decorate = ! hasDefaultSize() && ! YQUI::ui()->haveWM();
82
83 #if 0
84     if ( hasSmallDecorations() )
85     {
86         // None of this works (yet). :-((
87
88         clearWFlags( getWFlags() );
89         setWFlags( Qt::WStyle_Customize | Qt::WStyle_DialogBorder | Qt::WStyle_StaysOnTop );
90         // decorate = true;
91     }
92 #endif
93
94     if ( decorate )
95     {
96         _qFrame->setFrameStyle ( Q3Frame::Box | Q3Frame::Raised );
97         _qFrame->setLineWidth(2);
98         _qFrame->setMidLineWidth(3);
99     }
100     else
101     {
102         _qFrame->setFrameStyle ( Q3Frame::NoFrame );
103     }
104 }
105
106
107 YQDialog::~YQDialog()
108 {
109 }
110
111
112 int YQDialog::preferredWidth()
113 {
114     int preferredWidth;
115
116     if ( hasDefaultSize() )
117     {
118         if ( userResized() )
119             preferredWidth = _userSize.width();
120         else
121             preferredWidth = YQUI::ui()->defaultSize( YD_HORIZ );
122     }
123     else
124     {
125         preferredWidth = YDialog::preferredWidth() + 2 * decorationWidth();
126     }
127
128     int screenWidth = qApp->desktop()->width();
129
130     if ( preferredWidth > screenWidth )
131     {
132         y2warning( "Limiting dialog width to screen width (%d) instead of %d - check the layout!",
133                    screenWidth, preferredWidth );
134     }
135
136     return preferredWidth;
137 }
138
139
140 int YQDialog::preferredHeight()
141 {
142     int preferredHeight;
143
144     if ( hasDefaultSize() )
145     {
146         if ( userResized() )
147             preferredHeight = _userSize.height();
148         else
149             preferredHeight = YQUI::ui()->defaultSize( YD_VERT );
150     }
151     else
152     {
153         preferredHeight = YDialog::preferredHeight() + 2 * decorationWidth();
154     }
155
156     int screenHeight = qApp->desktop()->height();
157
158     if ( preferredHeight > screenHeight )
159     {
160         y2warning( "Limiting dialog height to screen height (%d) instead of %d - check the layout!",
161                    screenHeight, preferredHeight );
162     }
163
164     return preferredHeight;
165 }
166
167
168 int YQDialog::decorationWidth()
169 {
170     if ( ! hasDefaultSize() && _qFrame )
171         return _qFrame->frameWidth();
172     else
173         return 0;
174 }
175
176
177 void YQDialog::setEnabled( bool enabled )
178 {
179     QWidget::setEnabled( enabled );
180     YWidget::setEnabled( enabled );
181 }
182
183
184 void YQDialog::setSize( int newWidth, int newHeight )
185 {
186     if ( newWidth > qApp->desktop()->width() )
187         newWidth = qApp->desktop()->width();
188
189     if ( newHeight > qApp->desktop()->height() )
190         newHeight = qApp->desktop()->height();
191
192     if ( hasChildren() )
193     {
194         firstChild()->setSize( newWidth  - 2 * decorationWidth(),
195                                newHeight - 2 * decorationWidth() );
196
197         QWidget * qChild = (QWidget *) firstChild()->widgetRep();
198         qChild->move( decorationWidth(), decorationWidth() );
199     }
200
201     if ( _qFrame )
202         _qFrame->resize( newWidth, newHeight );
203
204     resize( newWidth, newHeight );
205 }
206
207
208
209 void YQDialog::activate( bool active )
210 {
211     if ( active )
212     {
213         if ( ! YQUI::ui()->haveWM() )
214         {
215             if ( YQUI::ui()->autoActivateDialogs() )
216                 setActiveWindow();
217             else
218                 y2milestone( "Auto-activating dialog window turned off" );
219         }
220
221         ensureOnlyOneDefaultButton();
222     }
223 }
224
225
226 void
227 YQDialog::resizeEvent( QResizeEvent * event )
228 {
229     if ( event )
230     {
231         setSize ( event->size().width(), event->size().height() );
232         _userSize    = event->size();
233         _userResized = true;
234     }
235 }
236
237
238 YQGenericButton *
239 YQDialog::findDefaultButton()
240 {
241     if ( _defaultButton )
242         return _defaultButton;
243
244     _defaultButton = findDefaultButton( childrenBegin(), childrenEnd() );
245
246     return _defaultButton;
247 }
248
249
250 YQGenericButton *
251 YQDialog::findDefaultButton( YWidgetListConstIterator begin,
252                              YWidgetListConstIterator end ) const
253
254 {
255     for ( YWidgetListConstIterator it = begin; it != end; ++it )
256     {
257         YWidget * widget = *it;
258
259         //
260         // Check this widget
261         //
262
263         YQGenericButton * button = dynamic_cast<YQGenericButton *> (widget);
264
265         if ( button && button->isDefaultButton() )
266         {
267             return button;
268         }
269
270
271         //
272         // Recurse over the children of this widget
273         //
274
275         if ( widget->hasChildren() )
276         {
277             button = findDefaultButton( widget->childrenBegin(),
278                                         widget->childrenEnd() );
279             if ( button )
280                 return button;
281         }
282     }
283
284     return 0;
285 }
286
287
288 YQWizard *
289 YQDialog::ensureOnlyOneDefaultButton( YWidgetListConstIterator begin,
290                                       YWidgetListConstIterator end )
291 {
292     YQGenericButton * def  = _focusButton ? _focusButton : _defaultButton;
293     YQWizard * wizard = 0;
294
295     for ( YWidgetListConstIterator it = begin; it != end; ++it )
296     {
297         YQGenericButton * button       = dynamic_cast<YQGenericButton *> (*it);
298         YQWizardButton  * wizardButton = dynamic_cast<YQWizardButton * > (*it);
299
300         if ( ! wizard )
301             wizard = dynamic_cast<YQWizard *> (*it);
302
303         if ( wizardButton )
304         {
305             wizardButton->showAsDefault( false );
306         }
307         else if ( button )
308         {
309             if ( button->isDefaultButton() )
310             {
311                 if ( _defaultButton && button != _defaultButton )
312                 {
313                     y2error( "Too many default buttons: [%s]",
314                              (const char *) button->text() );
315                     y2error( "Using old default button: [%s]",
316                              (const char *) _defaultButton->text() );
317                 }
318                 else
319                 {
320                     _defaultButton = button;
321                 }
322             }
323
324             if ( button->isShownAsDefault() && button != def )
325                 button->showAsDefault( false );
326         }
327
328         if ( (*it)->hasChildren() )
329         {
330             YQWizard * wiz = ensureOnlyOneDefaultButton( (*it)->childrenBegin(),
331                                                          (*it)->childrenEnd() );
332             if ( wiz )
333                 wizard = wiz;
334         }
335     }
336
337     return wizard;
338 }
339
340
341 void
342 YQDialog::ensureOnlyOneDefaultButton()
343 {
344     _defaultButton = 0;
345     YQWizard * wizard = ensureOnlyOneDefaultButton( childrenBegin(), childrenEnd() );
346
347     if ( ! _defaultButton && wizard )
348     {
349         _defaultButton = wizardDefaultButton( wizard );
350     }
351
352     YQGenericButton * def  = _focusButton ? _focusButton : _defaultButton;
353
354     if ( def )
355         def->showAsDefault();
356 }
357
358
359 YQWizard *
360 YQDialog::findWizard() const
361 {
362     return findWizard( childrenBegin(), childrenEnd() );
363 }
364
365
366 YQWizard *
367 YQDialog::findWizard( YWidgetListConstIterator begin,
368                       YWidgetListConstIterator end ) const
369
370 {
371     for ( YWidgetListConstIterator it = begin; it != end; ++it )
372     {
373         YWidget * widget = *it;
374         YQWizard * wizard = dynamic_cast<YQWizard *> (widget);
375
376         if ( wizard )
377             return wizard;
378
379         if ( widget->hasChildren() )
380         {
381             wizard = findWizard( widget->childrenBegin(),
382                                  widget->childrenEnd() );
383             if ( wizard )
384                 return wizard;
385         }
386     }
387
388     return 0;
389 }
390
391
392 YQGenericButton *
393 YQDialog::wizardDefaultButton( YQWizard * wizard ) const
394 {
395     YQGenericButton * def = 0;
396
397     if ( ! wizard )
398         wizard = findWizard();
399
400     if ( wizard )
401     {
402         // Pick one of the wizard buttons
403
404         if ( wizard->direction() == YQWizard::Backward )
405         {
406             if ( wizard->backButton()
407                  && wizard->backButton()->isShown()
408                  && wizard->backButton()->isEnabled() )
409             {
410                 def = wizard->backButton();
411             }
412         }
413
414         if ( ! def )
415         {
416             if ( wizard->nextButton()
417                  && wizard->nextButton()->isShown()
418                  && wizard->nextButton()->isEnabled() )
419             {
420                 def = wizard->nextButton();
421             }
422         }
423     }
424
425     return def;
426 }
427
428
429 void
430 YQDialog::setDefaultButton( YQGenericButton * newDefaultButton )
431 {
432     if ( _defaultButton   &&
433          newDefaultButton &&
434          newDefaultButton != _defaultButton )
435     {
436         if ( dynamic_cast<YQWizardButton *>( _defaultButton ) )
437         {
438             // Let app defined default buttons override wizard buttons
439             _defaultButton->setDefaultButton( false );
440         }
441         else
442         {
443             y2error( "Too many `opt(`default) PushButtons: [%s]",
444                      (const char *) newDefaultButton->text() );
445             newDefaultButton->setDefaultButton( false );
446             return;
447         }
448     }
449
450     _defaultButton = newDefaultButton;
451
452     if ( _defaultButton )
453     {
454         _defaultButton->setDefaultButton( true );
455         y2debug( "New default button: [%s]", (const char *) _defaultButton->text() );
456
457         if ( _defaultButton && ! _focusButton )
458             _defaultButton->showAsDefault( true );
459     }
460 }
461
462
463 bool
464 YQDialog::activateDefaultButton( bool warn )
465 {
466     // Try the focus button first, if there is any.
467
468     if ( _focusButton              &&
469          _focusButton->isEnabled() &&
470          _focusButton->isShownAsDefault() )
471     {
472         y2debug( "Activating focus button: [%s]", (const char *) _focusButton->text() );
473         _focusButton->activate();
474         return true;
475     }
476
477
478     // No focus button - try the default button, if there is any.
479
480     _defaultButton = findDefaultButton();
481
482     if ( _defaultButton                 &&
483          _defaultButton->isEnabled()    &&
484          _defaultButton->isShownAsDefault() )
485     {
486         y2debug( "Activating default button: [%s]", (const char *) _defaultButton->text() );
487         _defaultButton->activate();
488         return true;
489     }
490     else
491     {
492         if ( warn )
493         {
494             y2warning( "No default button in this dialog - ignoring [Return]" );
495         }
496     }
497
498     return false;
499 }
500
501
502 void
503 YQDialog::losingFocus( YQGenericButton * button )
504 {
505     if ( button == _focusButton )
506     {
507         if ( _focusButton && _focusButton != _defaultButton )
508             _focusButton->showAsDefault( false );
509
510         _focusButton = 0;
511     }
512
513     if ( ! _focusButton && _defaultButton )
514         _defaultButton->showAsDefault( true );
515 }
516
517
518 void
519 YQDialog::gettingFocus( YQGenericButton * button )
520 {
521     if ( _focusButton && _focusButton != button )
522         _focusButton->showAsDefault( false );
523
524     if ( _defaultButton && _defaultButton != button )
525         _defaultButton->showAsDefault( false );
526
527     _focusButton = button;
528
529     if ( _focusButton )
530         _focusButton->showAsDefault( true );
531 }
532
533
534 void
535 YQDialog::keyPressEvent( QKeyEvent * event )
536 {
537     if ( event )
538     {
539         if ( event->key() == Qt::Key_Print )
540         {
541             YQUI::ui()->makeScreenShot( "" );
542             return;
543         }
544         else if ( event->key() == Qt::Key_F5 )          // No matter if Ctrl/Alt/Shift pressed
545         {
546             YQUI::ui()->easterEgg();
547             return;
548         }
549         else if ( event->key()   == Qt::Key_F4 &&       // Shift-F4: toggle colors for vision impaired users
550                   event->state() == Qt::ShiftButton )
551         {
552             YQUI::ui()->toggleVisionImpairedPalette();
553
554             if ( YQUI::ui()->usingVisionImpairedPalette() )
555             {
556                 y2milestone( "Switched to vision impaired palette" );
557                 QMessageBox::information( 0,                                            // parent
558                                           _("Color switching"),                         // caption
559                                           _( "Switching to color palette for vision impaired users -\n"
560                                              "press Shift-F4 again to switch back to normal colors."   ), // text
561                                           QMessageBox::Ok | QMessageBox::Default,       // button0
562                                           QMessageBox::NoButton,                        // button1
563                                           QMessageBox::NoButton );                      // button2
564             }
565             return;
566         }
567         else if ( event->key()   == Qt::Key_F7 &&       // Shift-F7: toggle y2debug logging
568                   event->state() == Qt::ShiftButton )
569         {
570             YQUI::ui()->askConfigureLogging();
571             return;
572         }
573         else if ( event->key()   == Qt::Key_F8 &&       // Shift-F8: save y2logs
574                   event->state() == Qt::ShiftButton )
575         {
576             YQUI::ui()->askSaveLogs();
577             return;
578         }
579         else if ( event->state() == 0 )                 // No Ctrl / Alt / Shift etc. pressed
580         {
581             if ( event->key() == Qt::Key_Return ||
582                  event->key() == Qt::Key_Enter    )
583             {
584                 ( void ) activateDefaultButton();
585                 return;
586             }
587         }
588         else if ( event->state() == ( Qt::ControlButton | Qt::ShiftButton | Qt::AltButton ) )
589         {
590             // Qt-UI special keys - all with Ctrl-Shift-Alt
591
592             y2milestone( "Caught YaST2 magic key combination" );
593
594             if ( event->key() == Qt::Key_M )
595             {
596                 YQUI::ui()->toggleRecordMacro();
597                 return;
598             }
599             else if ( event->key() == Qt::Key_P )
600             {
601                 YQUI::ui()->askPlayMacro();
602                 return;
603             }
604             else if ( event->key() == Qt::Key_D )
605             {
606                 YQUI::ui()->sendEvent( new YDebugEvent() );
607                 return;
608             }
609             else if ( event->key() == Qt::Key_X )
610             {
611                 y2milestone( "Starting xterm" );
612                 system( "/usr/bin/xterm &" );
613                 return;
614             }
615         }
616     }
617
618     QWidget::keyPressEvent( event );
619 }
620
621
622 void YQDialog::closeEvent( QCloseEvent * event )
623 {
624     // The window manager "close window" button ( and menu, e.g. Alt-F4 ) will be
625     // handled just like the user had clicked on the `id`( `cancel ) button in
626     // that dialog. It's up to the YCP application to handle this ( if desired ).
627
628     y2debug( "Ignoring window manager close button." );
629     event->ignore();
630     YQUI::ui()->sendEvent( new YCancelEvent() );
631 }
632
633
634 void YQDialog::focusInEvent( QFocusEvent * event )
635 {
636
637     // The dialog itself doesn't need or want the keyboard focus, but obviously
638     // ( since Qt 2.3? ) it needs QFocusPolicy::StrongFocus for the default
639     // button mechanism to work. So let's accept the focus and give it to some
640     // child widget.
641
642     if ( event->reason() == Qt::TabFocusReason )
643     {
644         focusNextPrevChild( true );
645     }
646     else
647     {
648         if ( _defaultButton )
649             _defaultButton->setKeyboardFocus();
650         else
651             focusNextPrevChild( true );
652     }
653 }
654
655
656 void
657 YQDialog::show()
658 {
659     if ( ! hasDefaultSize() && qApp->mainWidget()->isVisible() )
660             center( this, qApp->mainWidget() );
661     else if ( isCentered() )
662         center( this, qApp->desktop() );
663
664     QWidget::show();
665 }
666
667
668 void
669 YQDialog::center( QWidget * dialog, QWidget * parent )
670 {
671     if ( ! dialog )
672         return;
673
674     if ( ! parent )
675     {
676         if ( dialog == qApp->mainWidget() )
677             parent = qApp->desktop();
678         else
679             parent = qApp->mainWidget();
680     }
681
682     QPoint pos( ( parent->width()  - dialog->width()  ) / 2,
683                 ( parent->height() - dialog->height() ) / 2 );
684
685     pos += parent->mapToGlobal( QPoint( 0, 0 ) );
686     pos = dialog->mapToParent( dialog->mapFromGlobal( pos ) );
687     dialog->move( pos );
688 }
689
690
691
692 #include "YQDialog.moc"