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