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