]> icculus.org git repositories - duncan/yast2-qt4.git/blob - src/YQDialog.cc
don't create QObjects in ycp thread - make timeouts work
[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     : QWidget( chooseParent( dialogType ),
50                dialogType == YMainDialog ? YQMainDialogWFlags : YQPopupDialogWFlags )
51     , YDialog( dialogType, colorMode )
52 {
53     setWidgetRep( this );
54
55     _userResized        = false;
56     _focusButton        = 0;
57     _defaultButton      = 0;
58
59     setWindowTitle( "YaST2" );
60     setFocusPolicy( Qt::StrongFocus );
61
62     if ( colorMode != YDialogNormalColor )
63     {
64         QColor normalBackground     ( 0, 128, 0 );
65         QColor inputFieldBackground ( 0xbb,  0xff, 0xbb );
66         QColor text = Qt::white;
67
68         if ( colorMode == YDialogInfoColor )
69         {
70             normalBackground = QColor ( 238, 232, 170 ); // PaleGoldenrod
71         }
72
73         QPalette warnPalette( normalBackground );
74         warnPalette.setColor( QPalette::Text, text );
75         warnPalette.setColor( QPalette::Base, inputFieldBackground );
76         setPalette( warnPalette );
77     }
78
79     if ( dialogType == YMainDialog &&
80          QWidget::parent() != YQMainWinDock::mainWinDock() )
81     {
82         setWindowFlags( YQPopupDialogWFlags );
83     }
84
85     if ( QWidget::parent() == YQMainWinDock::mainWinDock() )
86     {
87         YQMainWinDock::mainWinDock()->add( this );
88     }
89 }
90
91
92 YQDialog::~YQDialog()
93 {
94     if ( dialogType() == YMainDialog )
95     {
96         YQMainWinDock::mainWinDock()->remove( this );
97     }
98     if ( _defaultButton )
99        _defaultButton->forgetDialog();
100     if ( _focusButton )
101        _focusButton->forgetDialog();
102 }
103
104
105 QWidget *
106 YQDialog::chooseParent( YDialogType dialogType )
107 {
108     QWidget * parent = 0;
109
110     if ( dialogType == YMainDialog &&
111          YQMainWinDock::mainWinDock()->couldDock() )
112     {
113         y2debug( "Adding dialog to mainWinDock" );
114         parent = YQMainWinDock::mainWinDock();
115     }
116
117     return parent;
118 }
119
120
121 int
122 YQDialog::preferredWidth()
123 {
124     int preferredWidth;
125
126     if ( dialogType() == YMainDialog )
127     {
128         if ( userResized() )
129             preferredWidth = _userSize.width();
130         else
131             preferredWidth = YQUI::ui()->defaultSize( YD_HORIZ );
132     }
133     else
134     {
135         preferredWidth = YDialog::preferredWidth();
136     }
137
138     int screenWidth = qApp->desktop()->width();
139
140     if ( preferredWidth > screenWidth )
141     {
142         y2warning( "Limiting dialog width to screen width (%d) instead of %d - check the layout!",
143                    screenWidth, preferredWidth );
144     }
145
146     return preferredWidth;
147 }
148
149
150 int
151 YQDialog::preferredHeight()
152 {
153     int preferredHeight;
154
155     if ( dialogType() == YMainDialog )
156     {
157         if ( userResized() )
158             preferredHeight = _userSize.height();
159         else
160             preferredHeight = YQUI::ui()->defaultSize( YD_VERT );
161     }
162     else
163     {
164         preferredHeight = YDialog::preferredHeight();
165     }
166
167     int screenHeight = qApp->desktop()->height();
168
169     if ( preferredHeight > screenHeight )
170     {
171         y2warning( "Limiting dialog height to screen height (%d) instead of %d - check the layout!",
172                    screenHeight, preferredHeight );
173     }
174
175     return preferredHeight;
176 }
177
178
179 void
180 YQDialog::setEnabled( bool enabled )
181 {
182     QWidget::setEnabled( enabled );
183     YDialog::setEnabled( enabled );
184 }
185
186
187 void
188 YQDialog::setSize( int newWidth, int newHeight )
189 {
190     // y2debug( "Resizing dialog to %d x %d", newWidth, newHeight );
191
192     if ( newWidth > qApp->desktop()->width() )
193         newWidth = qApp->desktop()->width();
194
195     if ( newHeight > qApp->desktop()->height() )
196         newHeight = qApp->desktop()->height();
197
198     if ( hasChildren() )
199     {
200         ( ( QWidget* )firstChild()->widgetRep() )->show();
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"