- Don't create layouts with parent. Qt 4.x automatically reparents
[duncan/yast2-qt4.git] / src / YQApplication.cc
1 /*---------------------------------------------------------------------\
2 |                                                                      |
3 |                      __   __    ____ _____ ____                      |
4 |                      \ \ / /_ _/ ___|_   _|___ \                     |
5 |                       \ V / _` \___ \ | |   __) |                    |
6 |                        | | (_| |___) || |  / __/                     |
7 |                        |_|\__,_|____/ |_| |_____|                    |
8 |                                                                      |
9 |                               core system                            |
10 |                                                        (C) SuSE GmbH |
11 \----------------------------------------------------------------------/
12
13   File:         YQApplication.cc
14
15   Author:       Stefan Hundhammer <sh@suse.de>
16
17   Textdomain    "packages-qt"
18 /-*/
19
20
21 #include <QApplication>
22 #include <QLocale>
23 #include <unistd.h>     // access()
24 #include <qregexp.h>
25 #include <qfiledialog.h>
26 #include <qmessagebox.h>
27
28 #define y2log_component "qt-ui"
29 #include <ycp/y2log.h>
30
31 #include "utf8.h"
32 #include "YQi18n.h"
33
34 #include "YQApplication.h"
35
36
37 YQApplication::YQApplication()
38     : YApplication()
39     , _currentFont( 0 )
40     , _headingFont( 0 )
41     , _boldFont( 0 )
42     , _fontFamily( "Sans Serif" )
43     , _langFonts( 0 )
44     , _qtTranslations( 0 )
45     , _autoFonts( false )
46     , _autoNormalFontSize( -1 )
47     , _autoHeadingFontSize( -1 )
48 {
49     y2debug( "YQApplication constructor start" );
50
51     setIconBasePath( ICONDIR "/icons/22x22/apps/" );
52     loadPredefinedQtTranslations();
53
54     y2debug( "YQApplication constructor end" );
55 }
56
57
58 YQApplication::~YQApplication()
59 {
60     if ( _langFonts )
61         delete _langFonts;
62
63     if ( _qtTranslations )
64         delete _qtTranslations;
65
66     deleteFonts();
67 }
68
69
70 void
71 YQApplication::setLanguage( const string & language,
72                             const string & encoding )
73 {
74     YApplication::setLanguage( language, encoding );
75     loadPredefinedQtTranslations();
76     setLangFonts( language, encoding );
77 }
78
79
80
81 void
82 YQApplication::loadPredefinedQtTranslations()
83 {
84     QString path = QT_LOCALEDIR;
85     QString language = QLocale::system().name();
86
87     QString transFile = QString( "qt_%1.qm")
88               .arg( language.toLower().replace('_','-') );
89
90     if ( path.isEmpty() )
91     {
92         y2warning( "Qt locale directory not set - "
93                    "no translations for predefined Qt dialogs" );
94         return;
95     }
96
97     if ( ! _qtTranslations )
98         _qtTranslations = new QTranslator();
99
100     _qtTranslations->load( transFile, path );
101
102     if ( _qtTranslations->isEmpty() )
103     {
104         // try fallback
105         transFile = QString( "qt_%1.qm").arg( language.toLower().left(2) );
106         _qtTranslations->load( transFile, path );
107     }
108
109     if ( _qtTranslations->isEmpty() )
110     {
111         y2warning( "Can't load translations for predefined Qt dialogs from %s/%s",
112                    qPrintable(path), qPrintable(transFile) );
113     }
114     else
115     {
116         y2milestone( "Loaded translations for predefined Qt dialogs from %s/%s",
117                      qPrintable(path), qPrintable(transFile) );
118
119         qApp->installTranslator( _qtTranslations );
120     }
121
122
123     // Force reverse layout for Arabic and Hebrew
124
125     if ( ( language.startsWith( "ar" ) ||       // Arabic
126            language.startsWith( "he" ) )        // Hebrew
127          && ! (qApp->layoutDirection() == Qt::RightToLeft) )
128     {
129         y2warning( "Using fallback rule for reverse layout for language '%s'",
130                    qPrintable(language) );
131
132         qApp->setLayoutDirection( Qt::RightToLeft );
133     }
134 }
135
136
137 void
138 YQApplication::setLangFonts( const string & language, const string & encoding )
139 {
140     QString oldFontFamily = _fontFamily;
141
142     if ( ! _langFonts )
143     {
144         _langFonts = new QY2Settings( LANG_FONTS_FILE );
145         Q_CHECK_PTR( _langFonts );
146
147         if ( _langFonts->readError() )
148             y2error( "Error reading %s", qPrintable(_langFonts->fileName()) );
149         else
150             y2milestone( "%s read OK", qPrintable(_langFonts->fileName()) );
151     }
152
153     QString lang = language.c_str();
154
155     if ( ! encoding.empty() )
156         lang += QString( "." ) + encoding.c_str();
157
158     QString key;
159
160     if ( ! _langFonts->hasKey( fontKey( lang ) ) )      // Try with encoding ("zh_CN.UTF8" etc.)
161     {
162         lang = language.c_str();                        // Try without encoding ("zh_CN")
163
164         if ( ! _langFonts->hasKey( fontKey( lang ) ) )
165             lang.replace( QRegExp( "_.*$" ), "" );      // Cut off trailing country ("_CN")
166     }
167
168     if ( _langFonts->hasKey( fontKey( lang ) ) )
169     {
170         _fontFamily = _langFonts->get( fontKey( lang ), "Sans Serif" );
171         y2milestone( "%s = \"%s\"", qPrintable(fontKey( lang )), qPrintable(_fontFamily) );
172     }
173     else
174     {
175         _fontFamily = _langFonts->get( fontKey( "" ), "Sans Serif" );
176         y2milestone( "Using fallback for %s: font = \"%s\"",
177                      qPrintable(lang), qPrintable(_fontFamily) );
178     }
179
180     if ( _fontFamily != oldFontFamily && ! _fontFamily.isEmpty() )
181     {
182         y2milestone( "New font family: %s", qPrintable(_fontFamily) );
183         deleteFonts();
184         int size = qApp->font().pointSize();
185         QFont font( _fontFamily );
186         font.setPointSize( size );
187         qApp->setFont(font);    // font, informWidgets
188         y2milestone( "Reloading fonts - now using \"%s\"",
189                      qPrintable(font.toString()) );
190     }
191     else
192     {
193         y2debug( "No font change" );
194     }
195 }
196
197
198 QString
199 YQApplication::fontKey( const QString & lang )
200 {
201     if ( lang.isEmpty() )
202         return "font";
203     else
204         return QString( "font[%1]").arg( lang );
205 }
206
207
208 const QFont &
209 YQApplication::currentFont()
210 {
211     /**
212      * Brute force approach to make sure we'll really get a complete Unicode font:
213      * Explicitly load the one font that we made sure to contain all required
214      * characters, including Latin1, Latin2, Japanese, Korean, and the
215      * characters used for glyphs.
216      *
217      * There are many fonts that claim to be Unicode, but most of them contain
218      * just a sorry excuse for a complete Unicode character set. Qt can't know
219      * how complete a font is, so it chooses one that might be better in otherf
220      * aspects, but lacks necessary characters.
221      **/
222
223     if ( ! _currentFont )
224     {
225         if ( autoFonts() )
226         {
227             pickAutoFonts();
228
229             _currentFont = new QFont( _fontFamily );
230             _currentFont->setPixelSize( _autoNormalFontSize );
231             _currentFont->setWeight( QFont::Normal );
232
233             y2milestone( "Loaded %d pixel font: %s", _autoNormalFontSize,
234                          qPrintable(_currentFont->toString()) );
235
236             qApp->setFont( * _currentFont);     // font, informWidgets
237         }
238         else
239         {
240             // y2debug( "Copying QApplication::font()" );
241             _currentFont = new QFont( qApp->font() );
242         }
243     }
244
245     return * _currentFont;
246 }
247
248
249 const QFont &
250 YQApplication::boldFont()
251 {
252     if ( ! _boldFont )
253     {
254         _boldFont = new QFont( currentFont() );
255         _boldFont->setBold( true );
256     }
257
258     return * _boldFont;
259 }
260
261
262 const QFont &
263 YQApplication::headingFont()
264 {
265     /**
266      * Brute force load the heading font - see currentFont() above for more.
267      **/
268
269     if ( ! _headingFont )
270     {
271         if ( autoFonts() )
272         {
273             pickAutoFonts();
274
275             _headingFont = new QFont( _fontFamily );
276             _headingFont->setPixelSize( _autoHeadingFontSize );
277             _headingFont->setWeight( QFont::Bold );
278
279             y2milestone( "Loaded %d pixel bold font: %s", _autoHeadingFontSize,
280                          qPrintable(_headingFont->toString()) );
281         }
282         else
283         {
284             _headingFont = new QFont( _fontFamily, 14, QFont::Bold );
285         }
286     }
287
288     return * _headingFont;
289 }
290
291
292 void
293 YQApplication::deleteFonts()
294 {
295     if ( _currentFont )
296         delete _currentFont;
297
298     if ( _headingFont )
299         delete _headingFont;
300
301     if ( _boldFont )
302         delete _boldFont;
303
304     _currentFont = 0;
305     _headingFont = 0;
306     _boldFont    = 0;
307 }
308
309
310 void
311 YQApplication::setAutoFonts( bool useAutoFonts )
312 {
313     _autoFonts = useAutoFonts;
314 }
315
316
317 void
318 YQApplication::pickAutoFonts()
319 {
320     if ( _autoNormalFontSize >= 0 )     // Use cached values
321         return;
322
323 #warning FIXME: defaultSize
324 #if 0
325     int x = _default_size.width();
326     int y = _default_size.height();
327 #endif
328     int x = 800;
329     int y = 600;
330
331     int normal  = 10;
332     int heading = 12;
333
334     if ( x >= 800 && y >= 600 )
335     {
336         normal  = 10;
337         heading = 12;
338     }
339
340     if ( x >= 1024 && y >= 768 )
341     {
342         normal  = 12;
343         heading = 14;
344     }
345
346     if ( x >= 1280 && y >= 1024 )
347     {
348         normal  = 14;
349         heading = 18;
350     }
351
352     if ( x >= 1400 )
353     {
354         normal  = 16;
355         heading = 20;
356     }
357
358     if ( x >= 1600 )
359     {
360         normal  = 18;
361         heading = 24;
362     }
363
364     if ( x >= 2048 )    // Sounds futuristic? Just wait one or two years...
365     {
366         normal  = 20;
367         heading = 28;
368     }
369
370     _autoNormalFontSize  = normal;
371     _autoHeadingFontSize = heading;
372
373     y2milestone( "Selecting auto fonts - normal: %d, heading: %d (bold)",
374                  _autoNormalFontSize, _autoHeadingFontSize );
375 }
376
377
378 string
379 YQApplication::askForExistingDirectory( const string & startDir,
380                                         const string & headline )
381 {
382 #if 0
383     normalCursor();
384 #endif
385
386     QString dirName =
387         QFileDialog::getExistingDirectory( 0,
388                                            fromUTF8( startDir ),
389                                            fromUTF8( headline ) );      // caption
390 #if 0
391     busyCursor();
392 #endif
393
394     return toUTF8( dirName );
395 }
396
397
398 string
399 YQApplication::askForExistingFile( const string & startWith,
400                                    const string & filter,
401                                    const string & headline )
402 {
403 #if 0
404     normalCursor();
405 #endif
406
407     QString fileName =
408         QFileDialog::getOpenFileName( 0, fromUTF8( startWith ),
409                                       fromUTF8( filter ),
410                                       fromUTF8( headline ) );   // caption
411
412 #if 0
413     busyCursor();
414 #endif
415
416     return toUTF8( fileName );
417 }
418
419
420 string
421 YQApplication::askForSaveFileName( const string & startWith,
422                                    const string & filter,
423                                    const string & headline )
424 {
425 #if 0
426     normalCursor();
427 #endif
428
429     QString fileName = askForSaveFileName( fromUTF8( startWith ),
430                                            fromUTF8( filter ),
431                                            fromUTF8( headline ) );
432 #if 0
433     busyCursor();
434 #endif
435
436     return toUTF8( fileName );
437 }
438
439
440
441 QString
442 YQApplication::askForSaveFileName( const QString & startWith,
443                                    const QString & filter,
444                                    const QString & headline )
445 {
446     QString fileName;
447     bool tryAgain = false;
448
449     do
450     {
451         // Leave the mouse cursor alone - this function might be called from
452         // some other widget, not only from UI::AskForSaveFileName().
453
454         fileName = QFileDialog::getSaveFileName( 0, startWith,
455                                                  filter,
456                                                  headline );            // caption
457
458         if ( fileName.isEmpty() )       // this includes fileName.isNull()
459             return QString::null;
460
461
462         if ( access( QFile::encodeName( fileName ), F_OK ) == 0 )       // file exists?
463         {
464             QString msg;
465
466             if ( access( QFile::encodeName( fileName ), W_OK ) == 0 )
467             {
468                 // Confirm if the user wishes to overwrite an existing file
469                 msg = ( _( "%1 exists! Really overwrite?" ) ).arg( fileName );
470             }
471             else
472             {
473                 // Confirm if the user wishes to overwrite a write-protected file %1
474                 msg = ( _( "%1 exists and is write-protected!\nReally overwrite?" ) ).arg( fileName );
475             }
476
477             int buttonNo = QMessageBox::information( 0, // parent widget
478                                                      // Translators: Window title for confirmation dialog
479                                                      _( "Confirm"   ),
480                                                      msg,
481                                                      _( "C&ontinue" ),
482                                                      _( "&Cancel"   ) );
483             tryAgain = ( buttonNo != 0 );
484         }
485
486     } while ( tryAgain );
487
488     return fileName;
489 }
490
491
492 #include "YQApplication.moc"