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