34c80a7d388f87b2c43bb5247d6f0993aea95f2b
[duncan/yast2-qt4.git] / src / YQUI.h
1 /*---------------------------------------------------------------------\
2 |                                                                      |
3 |                      __   __    ____ _____ ____                      |
4 |                      \ \ / /_ _/ ___|_   _|___ \                     |
5 |                       \ V / _` \___ \ | |   __) |                    |
6 |                        | | (_| |___) || |  / __/                     |
7 |                        |_|\__,_|____/ |_| |_____|                    |
8 |                                                                      |
9 |                               core system                            |
10 |                                                        (C) SuSE GmbH |
11 \----------------------------------------------------------------------/
12
13   File:         YQUI.h
14
15   Author:       Stefan Hundhammer <sh@suse.de>
16
17 /-*/
18
19 #ifndef YQUI_h
20 #define YQUI_h
21
22 #include <qapplication.h>
23 #include <QMap>
24 #include <QTimer>
25 #include <QPalette>
26 #include <vector>
27
28 #include "YSimpleEventHandler.h"
29 #include <YUI.h>
30
31 #define YQWidgetMargin  4
32 #define YQWidgetSpacing 4
33 #define YQButtonBorder  3
34
35 class QCursor;
36 class QFrame;
37 class QStackedWidget;
38 class QY2Settings;
39 class YEvent;
40 class YQOptionalWidgetFactory;
41 class YQPackageSelectorPlugin;
42 class YQWidgetFactory;
43 class YQApplication;
44
45 using std::string;
46 using std::vector;
47
48
49 class YQUI: public QObject, public YUI
50 {
51     Q_OBJECT
52 public:
53
54     /**
55      * Constructor.
56      **/
57     YQUI( int           argc,
58           char **       argv,
59           bool          with_threads,
60           const char *  macro_file );
61
62     /**
63      * Destructor.
64      **/
65     ~YQUI();
66
67     /**
68      * Access the global Qt-UI.
69      **/
70     static YQUI * ui() { return _ui; }
71
72
73 protected:
74     /**
75      * Create the widget factory that provides all the createXY() methods for
76      * standard (mandatory, i.e. non-optional) widgets.
77      *
78      * Reimplemented from YUI.
79      **/
80     virtual YWidgetFactory * createWidgetFactory();
81
82     /**
83      * Create the widget factory that provides all the createXY() methods for
84      * optional ("special") widgets and the corresponding hasXYWidget()
85      * methods.
86      *
87      * Reimplemented from YUI.
88      **/
89     virtual YOptionalWidgetFactory * createOptionalWidgetFactory();
90
91     /*
92      * Create the YApplication object that provides global methods.
93      *
94      * Reimplemented from YUI.
95      **/
96     virtual YApplication * createApplication();
97
98 public:
99
100     /**
101      * Return the global YApplication object as YQApplication.
102      *
103      * This will create the Y(Q)Application upon the first call and return a
104      * pointer to the one and only (singleton) Y(Q)Application upon each
105      * subsequent call.  This may throw exceptions if the Y(Q)Application
106      * cannot be created.
107      **/
108     static YQApplication * yqApp();
109
110     /**
111      * Widget event handlers (slots) call this when an event occured that
112      * should be the answer to a UserInput() / PollInput() (etc.) call.
113      *
114      * The UI assumes ownership of the event object that 'event' points to.
115      * In particular, it takes care to delete that object.
116      *
117      * It is an error to pass 0 for 'event'.
118      **/
119     void sendEvent( YEvent * event );
120
121     /**
122      * Returns 'true' if there is any event pending for the specified widget.
123      **/
124     bool eventPendingFor( YWidget * widget ) const
125         { return _event_handler.eventPendingFor( widget ); }
126
127     /**
128      * Returns the last event that isn't processed yet or 0 if there is none.
129      *
130      * The Qt UI keeps track of only one single (the last one) event.
131      **/
132     YEvent * pendingEvent() const { return _event_handler.pendingEvent(); }
133
134     /**
135      * Returns 'false" if the "--no-wm" was specified on the command line, i.e.
136      * we should assume no window manager is running.
137      **/
138     bool haveWM() const { return _have_wm; }
139
140     /**
141      * Returns 'true' if defaultsize windows should use the full screen.
142      **/
143     bool fullscreen() const { return _fullscreen; }
144
145     /**
146      * Returns 'false' if toplevel (defaultsize) windows should not get window
147      * manager decorations, i.e. "--noborder" was specified on the command
148      * line.
149      **/
150     bool decorateToplevelWindow() const { return _decorate_toplevel_window; }
151
152     /**
153      * Returns 'true' if the UI had a fatal error that requires the application
154      * to abort.
155      **/
156     bool fatalError() const { return _fatal_error; }
157
158     /**
159      * Raise a fatal UI error. It will be delivered when it is safe to do so.
160      * The caller should make sure it can continue for some time until the
161      * error is delivered.
162      **/
163     void raiseFatalError() { _fatal_error = true; }
164
165     /**
166      * Returns size for `opt(`defaultsize) dialogs (in one dimension).
167      **/
168     int defaultSize( YUIDimension dim ) const;
169
170     /**
171      * Make a screen shot in .png format and save it to 'filename'.
172      * Opens a file selection box if 'filename' is empty.
173      **/
174     void makeScreenShot( string filename );
175
176     /**
177      * UI-specific runPkgSeleciton method: Start the package selection.
178      * This implementation does the same as UserInput().
179      *
180      * Reimplemented from YUI.
181      **/
182     YCPValue runPkgSelection( YWidget * packageSelector );
183
184     /**
185      * Toggle macro recording (activated by Ctrl-Shift-Alt-M):
186      * Stop macro recording if it is in progress,
187      * open a file selection box and ask for a macro file name to save to and
188      * start recording if no recording has been in progress.
189      **/
190     void toggleRecordMacro();
191
192     /**
193      * Open file selection box and ask for a macro file to play
194      * (activated by Ctrl-Shift-Alt-P)
195      **/
196     void askPlayMacro();
197
198     /**
199      * Issue an internal error: Open popup with that message and wait.
200      *
201      * Reimplemented from YUI.
202      **/
203     void internalError( const char * msg );
204
205
206     /**
207      * Block WM_CLOSE events for the main window.
208      **/
209     void blockWmClose()         { _wm_close_blocked = true;  }
210
211     /**
212      * Unblock WM_CLOSE events for the main window.
213      **/
214     void unblockWmClose()       { _wm_close_blocked = false; }
215
216     /**
217      * Check if dialogs are to be activated automatically
218      **/
219     bool autoActivateDialogs() const { return _auto_activate_dialogs; }
220
221     /**
222      * Change automatic dialog activation
223      **/
224     void setAutoActivateDialogs( bool activate )
225         { _auto_activate_dialogs = activate; }
226
227     /**
228      * Block (or unblock) events. If events are blocked, any event sent
229      * should be ignored until events are unblocked again.
230      *
231      * Reimplemented from YUI.
232      **/
233     virtual void blockEvents( bool block = true );
234
235     /**
236      * Returns 'true' if events are currently blocked.
237      *
238      * Reimplemented from YUI.
239      **/
240     virtual bool eventsBlocked() const;
241
242     /**
243      * Returns the current product name
244      * ("SuSE Linux", "SuSE Linux Enterprise Server", "United Linux", etc.)
245      * as QString.
246      **/
247     QString productName() const;
248
249     /**
250      * Beep - activate the system (X11) bell.
251      *
252      * Reimplemented from YUI.
253      **/
254     void beep();
255
256
257 public slots:
258
259     /**
260      * Show hourglass cursor.
261      *
262      * Reimplemented from YUI.
263      **/
264     void busyCursor();
265
266     /**
267      * Show pointer cursor.
268      *
269      * Reimplemented from YUI.
270      **/
271     void normalCursor();
272
273     /**
274      * Open file selection box and let the user Save y2logs to that location.
275      * (Shift-F8)
276      **/
277     void askSaveLogs();
278
279     /**
280      * Open dialog to configure logging.
281      * (Shift-F7)
282      **/
283     void askConfigureLogging();
284
285     /**
286      * Fun stuff (release dependent)
287      **/
288     void easterEgg();
289
290     /**
291      * A mouse click with the wrong mouse button was detected - e.g., a right
292      * click on a push button. The user might be left-handed, but his mouse
293      * might not (yet) be configured for left-handed use - e.g., during
294      * installation. Ask him if he would like his mouse temporarily configured
295      * as a left-handed mouse.
296      *
297      * This status can be queried with UI::GetDisplayInfo() ("LeftHandedMouse").
298      **/
299     void maybeLeftHandedUser();
300
301
302 signals:
303     /**
304      * Emitted upon WM_CLOSE
305      **/
306     void wmClose();
307
308
309 protected:
310
311     /**
312      * Idle around until fd_ycp is readable and handle repaints.
313      * This is only used when a separate ui thread is running.
314      *
315      * Reimplemented from YUI.
316      **/
317     void idleLoop( int fd_ycp );
318
319     /**
320      * Return a representation for the glyph symbol specified in UTF-8 encoding
321      * or an empty string to get a default textual representation.
322      *
323      * Reimplemented from YUI.
324      **/
325     YCPString glyph( const YCPSymbol & glyphSymbol );
326
327     /**
328      * Go into event loop until next user input is available.
329      *
330      * Reimplemented from YUI.
331      **/
332     YEvent * userInput( unsigned long timeout_millisec = 0 );
333
334     /**
335      * Check the event queue for user input. Don't wait.
336      *
337      * Reimplemented from YUI.
338      **/
339     YEvent * pollInput();
340
341     /**
342      * Show and activate a dialog.
343      *
344      * Reimplemented from YUI.
345      **/
346     void showDialog( YDialog * dialog );
347
348     /**
349      * Decativate and close a dialog. This does not delete the dialog yet.
350      *
351      * Reimplemented from YUI.
352      **/
353     void closeDialog( YDialog * dialog );
354
355     /**
356      * Grab show events and work around QWidgetStack bug.
357      *
358      * Reimplemented from QObject.
359      **/
360     bool eventFilter( QObject * obj, QEvent * ev );
361
362     /**
363      * Make all UI windows usable without a mouse - even predefined Qt dialogs
364      * that don't know the UI's dialogs' activate() magic.
365      *
366      * Reimplemented from QObject.
367      **/
368     bool showEventFilter( QObject * obj, QEvent * ev );
369
370
371 public:
372
373     /**
374      *
375      * Open a directory selection box and prompt the user for an existing directory.
376      * [Reimplemented from YUI]
377      *
378      * 'startDir' is the initial directory that is displayed.
379      *
380      * 'headline' is an explanatory text for the directory selection box.
381      * Graphical UIs may omit that if no window manager is running.
382      *
383      * Returns the selected directory name
384      * or 'nil' (YCPVoid() ) if the user canceled the operation.
385      **/
386     YCPValue askForExistingDirectory ( const YCPString & startDir,
387                                        const YCPString & headline );
388
389     /**
390      * Open a file selection box and prompt the user for an existing file.
391      * [Reimplemented from YUI]
392      *
393      * 'startWith' is the initial directory or file.
394      *
395      * 'filter' is one or more blank-separated file patterns, e.g. "*.png *.jpg"
396      *
397      * 'headline' is an explanatory text for the file selection box.
398      * Graphical UIs may omit that if no window manager is running.
399      *
400      * Returns the selected file name
401      * or 'nil' (YCPVoid() ) if the user canceled the operation.
402      **/
403     YCPValue askForExistingFile ( const YCPString & startWith,
404                                   const YCPString & filter,
405                                   const YCPString & headline );
406
407     /**
408      * Open a file selection box and prompt the user for a file to save data to.
409      * Automatically asks for confirmation if the user selects an existing file.
410      * [Reimplemented from YUI]
411      *
412      * 'startWith' is the initial directory or file.
413      *
414      * 'filter' is one or more blank-separated file patterns, e.g. "*.png *.jpg"
415      *
416      * 'headline' is an explanatory text for the file selection box.
417      * Graphical UIs may omit that if no window manager is running.
418      *
419      * Returns the selected file name
420      * or 'nil' (YCPVoid() ) if the user canceled the operation.
421      **/
422     YCPValue askForSaveFileName ( const YCPString & startWith,
423                                   const YCPString & filter,
424                                   const YCPString & headline );
425
426     /**
427      * Lower-level version that works with QStrings and does not change
428      * the mouse cursor.
429      **/
430     QString askForSaveFileName( const QString & startWith,
431                                 const QString & filter,
432                                 const QString & headline );
433
434     /**
435      * main widget
436      **/
437     QWidget* mainWidget();
438
439     /**
440      * Initialize and set a textdomain for gettext()
441      **/
442     static void setTextdomain( const char * domain );
443
444     /**
445      * Returns a high-contrast color palette suitable for vision impaired users.
446      **/
447     static QPalette visionImpairedPalette();
448
449     /**
450      * Returns the normal color palette
451      **/
452     QPalette normalPalette() const { return _normalPalette; }
453
454     /**
455      * Toggle between the vision impaired and the normal color palette.
456      **/
457     void toggleVisionImpairedPalette();
458
459     /**
460      * Returns 'true' if high-contrast colors for vision impaired users is in use.
461      * This should be queried at other places before using custom colors.
462      **/
463     bool usingVisionImpairedPalette() const { return _usingVisionImpairedPalette; }
464
465     /**
466      * Convert logical layout spacing units into device dependent units.
467      * A default size dialog is assumed to be 80x25 layout spacing units
468      * and 640x480 device dependent spacing units.
469      *
470      * Reimplemented from YUI.
471      **/
472     virtual int deviceUnits( YUIDimension dim, float layout_units );
473
474     /**
475      * Convert device dependent units into logical layout spacing units.
476      * A default size dialog is assumed to be 80x25 layout spacing units
477      * and 640x480 device dependent spacing units.
478      *
479      * Reimplemented from YUI.
480      **/
481     virtual float layoutUnits( YUIDimension dim, int device_units );
482
483     /**
484      * Returns the package selector plugin singleton of this UI or creates it
485      * (including loading the plugin lib) if it does not exist yet.
486      **/
487     YQPackageSelectorPlugin * packageSelectorPlugin();
488
489
490 protected:
491
492     /**
493      * Display capabilities.
494      * [Reimplemented from YUI]
495      * See UI builtin GetDisplayInfo() doc for details.
496      **/
497     int  getDisplayWidth();
498     int  getDisplayHeight();
499     int  getDisplayDepth();
500     long getDisplayColors();
501     int  getDefaultWidth();
502     int  getDefaultHeight();
503     bool textMode()                     { return false; }
504     bool hasImageSupport()              { return true;  }
505     bool hasLocalImageSupport()         { return true;  }
506     bool hasAnimationSupport()          { return true;  }
507     bool hasIconSupport()               { return false; }       // not yet
508     bool hasFullUtf8Support()           { return true;  }
509     bool richTextSupportsTable()        { return true; }
510     bool leftHandedMouse()              { return _leftHandedMouse; }
511
512
513     QMap<QString, int>  screenShotNo;
514     QString             screenShotNameTemplate;
515
516 protected slots:
517
518     /**
519      * Application shutdown
520      **/
521     bool close();
522
523     /**
524      * Timeout during TimeoutUserInput() / WaitForEvent()
525      **/
526     void userInputTimeout();
527
528 protected:
529
530     /**
531      * Handle command line args
532      **/
533     void processCommandLineArgs( int argc, char **argv );
534
535     /**
536      * Calculate size of `opt(`defaultsize) dialogs
537      **/
538     void calcDefaultSize();
539
540   void init_ui();
541
542     //
543     // Data members
544     //
545
546     /**
547      * Assume presence of a window manager
548      **/
549     bool _have_wm;
550
551     /**
552      * Use the entire available screen
553      **/
554     bool _fullscreen;
555
556     /**
557      * Decorate the toplevel window
558      **/
559     bool _decorate_toplevel_window;
560
561     /**
562      * Container for the widget stack. QWidgetStack cannot handle a WFlags
563      * argument, so this needs to be embedded into something else - and a QVBox
564      * at least handles all the sizeHint and resize stuff.
565      **/
566     QWidget * _main_win;
567
568     /**
569      * Stack for the Qt widgets inside the main window.
570      **/
571     QStackedWidget * _widget_stack;
572
573     /**
574      * Stack to keep track of the stacking order of popup dialogs.
575      **/
576     vector<QWidget *> _popup_stack;
577
578     /**
579      * Size for `opt(`defaultsize) dialogs.
580      **/
581     QSize _default_size;
582
583     /**
584      * This flag is set during @ref #userInput in order to tell
585      * @ref #returnNow to call exit_loop, which only may be called
586      * after enter_loop.
587      **/
588     bool _do_exit_loop;
589
590     /**
591      * Event loop object. Required since a YaST2 UI needs to react to commands
592      * from the YCP command stream as well as to X11 / Qt events.
593      **/
594     QEventLoop * _eventLoop;
595
596     /**
597      * Window manager close events blocked?
598      **/
599     bool _wm_close_blocked;
600
601     /**
602      * Force new dialogs to the foreground and grab the keyboard focus?
603      * (Only if running without a window manager)
604      **/
605     bool _auto_activate_dialogs;
606
607     /**
608      * Global reference to the UI
609      **/
610     static YQUI * _ui;
611
612     /**
613      * Indicate a fatal error that requires the UI to terminate
614      **/
615     bool _fatal_error;
616
617     /**
618      * Timer for TimeoutUserInput() / WaitForEvent().
619      **/
620     QTimer _user_input_timer;
621
622     /**
623      * Timer for delayed busy cursor
624      **/
625     QTimer *_busy_cursor_timer;
626
627     /**
628      * The handler for the single pending event this UI keeps track of
629      **/
630     YSimpleEventHandler _event_handler;
631
632     int blocked_level;
633
634     /**
635      * Saved normal palette
636      **/
637     QPalette _normalPalette;
638
639     /**
640      * Flag: currently using special palette for vision impaired users?
641      **/
642     bool _usingVisionImpairedPalette;
643
644     /**
645      * Flag: Does the user want to use a left-handed mouse?
646      **/
647     bool _leftHandedMouse;
648
649     /**
650      * Flag: Was the user already asked if he wants to use a left-handed mouse?
651      **/
652     bool _askedForLeftHandedMouse;
653
654     bool _ui_inited;
655     int _ui_argc;
656     char **_ui_argv;
657 };
658
659 #endif // YQUI_h