-rw-r--r-- | core/launcher/firstuse.cpp | 517 |
1 files changed, 517 insertions, 0 deletions
diff --git a/core/launcher/firstuse.cpp b/core/launcher/firstuse.cpp new file mode 100644 index 0000000..31b7923 --- a/dev/null +++ b/core/launcher/firstuse.cpp | |||
@@ -0,0 +1,517 @@ | |||
1 | /********************************************************************** | ||
2 | ** Copyright (C) 2000-2002 Trolltech AS. All rights reserved. | ||
3 | ** | ||
4 | ** This file is part of the Qtopia Environment. | ||
5 | ** | ||
6 | ** This file may be distributed and/or modified under the terms of the | ||
7 | ** GNU General Public License version 2 as published by the Free Software | ||
8 | ** Foundation and appearing in the file LICENSE.GPL included in the | ||
9 | ** packaging of this file. | ||
10 | ** | ||
11 | ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE | ||
12 | ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. | ||
13 | ** | ||
14 | ** See http://www.trolltech.com/gpl/ for GPL licensing information. | ||
15 | ** | ||
16 | ** Contact info@trolltech.com if any conditions of this licensing are | ||
17 | ** not clear to you. | ||
18 | ** | ||
19 | **********************************************************************/ | ||
20 | |||
21 | // I need access to some things you don't normally get access to. | ||
22 | |||
23 | #ifndef _MSC_VER | ||
24 | //### revise to allow removal of translators under MSVC | ||
25 | #define private public | ||
26 | #define protected public | ||
27 | #endif | ||
28 | #include "firstuse.h" | ||
29 | #include "inputmethods.h" | ||
30 | #include "applauncher.h" | ||
31 | #include "serverapp.h" | ||
32 | #include <qtopia/custom.h> | ||
33 | #if defined(QPE_NEED_CALIBRATION) | ||
34 | #include "../settings/calibrate/calibrate.h" | ||
35 | #endif | ||
36 | #include "documentlist.h" | ||
37 | |||
38 | #include <qtopia/resource.h> | ||
39 | #include <qtopia/qcopenvelope_qws.h> | ||
40 | #include <qtopia/qpeapplication.h> | ||
41 | #include <qtopia/config.h> | ||
42 | #include <qtopia/applnk.h> | ||
43 | #include <qtopia/mimetype.h> | ||
44 | #include <qtopia/fontmanager.h> | ||
45 | |||
46 | #include <qapplication.h> | ||
47 | #include <qfile.h> | ||
48 | #include <qpainter.h> | ||
49 | #include <qcstring.h> | ||
50 | #include <qsimplerichtext.h> | ||
51 | #include <qcolor.h> | ||
52 | #include <qpushbutton.h> | ||
53 | #include <qhbox.h> | ||
54 | #include <qlabel.h> | ||
55 | #include <qtimer.h> | ||
56 | |||
57 | #if defined( Q_WS_QWS ) | ||
58 | #include <qwsdisplay_qws.h> | ||
59 | #include <qgfx_qws.h> | ||
60 | #endif | ||
61 | |||
62 | #include <qwindowsystem_qws.h> | ||
63 | |||
64 | #include <stdlib.h> | ||
65 | #include <sys/types.h> | ||
66 | #if defined(Q_OS_LINUX) || defined(_OS_LINUX_) | ||
67 | #include <unistd.h> | ||
68 | #endif | ||
69 | |||
70 | |||
71 | struct { | ||
72 | bool enabled; | ||
73 | const char *app; | ||
74 | const char *start; | ||
75 | const char *stop; | ||
76 | const char *desc; | ||
77 | } | ||
78 | settingsTable [] = | ||
79 | { | ||
80 | { FALSE, "language", "raise()", "accept()", // No tr | ||
81 | QT_TR_NOOP("Language") }, | ||
82 | #ifndef Q_OS_WIN32 | ||
83 | { FALSE, "systemtime", "raise()", "accept()", // No tr | ||
84 | QT_TR_NOOP("Time and Date") }, | ||
85 | #endif | ||
86 | { FALSE, "addressbook", "editPersonalAndClose()", "accept()", // No tr | ||
87 | QT_TR_NOOP("Personal Information") }, | ||
88 | { FALSE, 0, 0, 0, 0 } | ||
89 | }; | ||
90 | |||
91 | |||
92 | FirstUse::FirstUse(QWidget* parent, const char * name, WFlags wf) : | ||
93 | QDialog( parent, name, TRUE, wf), | ||
94 | transApp(0), transLib(0), needCalibrate(FALSE), currApp(-1), | ||
95 | waitForExit(-1), waitingForLaunch(FALSE), needRestart(FALSE) | ||
96 | { | ||
97 | ServerApplication::allowRestart = FALSE; | ||
98 | // we force our height beyound the maximum (which we set anyway) | ||
99 | QRect desk = qApp->desktop()->geometry(); | ||
100 | setGeometry( 0, 0, desk.width(), desk.height() ); | ||
101 | |||
102 | connect(qwsServer, SIGNAL(newChannel(const QString&)), | ||
103 | this, SLOT(newQcopChannel(const QString&))); | ||
104 | |||
105 | // Create a DocumentList so appLauncher has appLnkSet to search | ||
106 | docList = new DocumentList( 0, FALSE ); | ||
107 | appLauncher = new AppLauncher( this ); | ||
108 | connect( appLauncher, SIGNAL(terminated(int, const QString&)), | ||
109 | this, SLOT(terminated(int, const QString&)) ); | ||
110 | |||
111 | // more hackery | ||
112 | // I will be run as either the main server or as part of the main server | ||
113 | QWSServer::setScreenSaverIntervals(0); | ||
114 | loadPixmaps(); | ||
115 | |||
116 | //check if there is a language program | ||
117 | #ifndef Q_OS_WIN32 | ||
118 | QString exeSuffix; | ||
119 | #else | ||
120 | QString exeSuffix(".exe"); | ||
121 | #endif | ||
122 | |||
123 | for ( int i = 0; settingsTable[i].app; i++ ) { | ||
124 | QString file = QPEApplication::qpeDir() + "bin/"; | ||
125 | file += settingsTable[i].app; | ||
126 | file += exeSuffix; | ||
127 | if ( QFile::exists(file) ) | ||
128 | settingsTable[i].enabled = TRUE; | ||
129 | } | ||
130 | |||
131 | setFocusPolicy(NoFocus); | ||
132 | |||
133 | taskBar = new QWidget(0, 0, WStyle_Tool | WStyle_Customize | WStyle_StaysOnTop | WGroupLeader); | ||
134 | |||
135 | inputMethods = new InputMethods(taskBar); | ||
136 | connect(inputMethods, SIGNAL(inputToggled(bool)), | ||
137 | this, SLOT(calcMaxWindowRect())); | ||
138 | |||
139 | back = new QPushButton(tr("<< Back"), taskBar); | ||
140 | back->setFocusPolicy(NoFocus); | ||
141 | connect(back, SIGNAL(clicked()), this, SLOT(previousDialog()) ); | ||
142 | |||
143 | next = new QPushButton(tr("Next >>"), taskBar); | ||
144 | next->setFocusPolicy(NoFocus); | ||
145 | connect(next, SIGNAL(clicked()), this, SLOT(nextDialog()) ); | ||
146 | |||
147 | // need to set the geom to lower corner | ||
148 | QSize sz = inputMethods->sizeHint(); | ||
149 | int buttonWidth = (width() - sz.width()) / 2; | ||
150 | int x = 0; | ||
151 | |||
152 | controlHeight = back->sizeHint().height(); | ||
153 | |||
154 | inputMethods->setGeometry(0,0, sz.width(), controlHeight ); | ||
155 | x += sz.width(); | ||
156 | |||
157 | back->setGeometry(x, 0, buttonWidth, controlHeight); | ||
158 | x += buttonWidth; | ||
159 | next->setGeometry(x, 0, buttonWidth, controlHeight); | ||
160 | |||
161 | taskBar->setGeometry( 0, height() - controlHeight, desk.width(), controlHeight); | ||
162 | taskBar->hide(); | ||
163 | |||
164 | #if defined(Q_WS_QWS) && !defined(QT_NO_COP) | ||
165 | qDebug("Setting up QCop to QPE/System"); | ||
166 | QCopChannel* sysChannel = new QCopChannel( "QPE/System", this ); | ||
167 | connect(sysChannel, SIGNAL(received(const QCString &, const QByteArray &)), | ||
168 | this, SLOT(message(const QCString &, const QByteArray &)) ); | ||
169 | #endif | ||
170 | calcMaxWindowRect(); | ||
171 | #if defined(QPE_NEED_CALIBRATION) | ||
172 | if ( !QFile::exists("/etc/pointercal") ) { | ||
173 | needCalibrate = TRUE; | ||
174 | grabMouse(); | ||
175 | } | ||
176 | #endif | ||
177 | Config config("locale"); | ||
178 | config.setGroup( "Language"); | ||
179 | lang = config.readEntry( "Language", "en"); | ||
180 | |||
181 | defaultFont = font(); | ||
182 | |||
183 | //###language/font hack; should look it up somewhere | ||
184 | #ifdef Q_WS_QWS | ||
185 | if ( lang == "ja" || lang == "zh_CN" || lang == "zh_TW" || lang == "ko" ) { | ||
186 | QFont fn = FontManager::unicodeFont( FontManager::Proportional ); | ||
187 | qApp->setFont( fn, TRUE ); | ||
188 | } | ||
189 | #endif | ||
190 | } | ||
191 | |||
192 | FirstUse::~FirstUse() | ||
193 | { | ||
194 | delete appLauncher; | ||
195 | delete docList; | ||
196 | delete taskBar; | ||
197 | ServerApplication::allowRestart = TRUE; | ||
198 | } | ||
199 | |||
200 | void FirstUse::calcMaxWindowRect() | ||
201 | { | ||
202 | #ifdef Q_WS_QWS | ||
203 | QRect wr; | ||
204 | int displayWidth = qApp->desktop()->width(); | ||
205 | QRect ir = inputMethods->inputRect(); | ||
206 | if ( ir.isValid() ) { | ||
207 | wr.setCoords( 0, 0, displayWidth-1, ir.top()-1 ); | ||
208 | } else { | ||
209 | wr.setCoords( 0, 0, displayWidth-1, | ||
210 | qApp->desktop()->height() - controlHeight-1); | ||
211 | } | ||
212 | |||
213 | #if QT_VERSION < 0x030000 | ||
214 | QWSServer::setMaxWindowRect( qt_screen->mapToDevice(wr, | ||
215 | QSize(qt_screen->width(),qt_screen->height())) | ||
216 | ); | ||
217 | #else | ||
218 | QWSServer::setMaxWindowRect( wr ); | ||
219 | #endif | ||
220 | #endif | ||
221 | } | ||
222 | |||
223 | /* cancel current dialog, and bring up next */ | ||
224 | void FirstUse::nextDialog() | ||
225 | { | ||
226 | int prevApp = currApp; | ||
227 | do { | ||
228 | currApp++; | ||
229 | qDebug( "currApp = %d", currApp ); | ||
230 | if ( settingsTable[currApp].app == 0 ) { | ||
231 | if ( prevApp >= 0 && appLauncher->isRunning(settingsTable[prevApp].app) ) { | ||
232 | // The last application is still running. | ||
233 | // Tell it to stop, and when its done we'll come back | ||
234 | // to nextDialog and exit. | ||
235 | qDebug( "Waiting for %s to exit", settingsTable[prevApp].app ); | ||
236 | QCopEnvelope e(QCString("QPE/Application/") + settingsTable[prevApp].app, | ||
237 | settingsTable[prevApp].stop ); | ||
238 | currApp = prevApp; | ||
239 | } else { | ||
240 | qDebug( "Done!" ); | ||
241 | Config config( "qpe" ); | ||
242 | config.setGroup( "Startup" ); | ||
243 | config.writeEntry( "FirstUse", FALSE ); | ||
244 | QPixmap pix = Resource::loadPixmap("bigwait"); | ||
245 | QLabel *lblWait = new QLabel(0, "wait hack!", // No tr | ||
246 | QWidget::WStyle_Customize | QWidget::WDestructiveClose | | ||
247 | QWidget::WStyle_NoBorder | QWidget::WStyle_Tool | | ||
248 | QWidget::WStyle_StaysOnTop); | ||
249 | lblWait->setPixmap( pix ); | ||
250 | lblWait->setAlignment( QWidget::AlignCenter ); | ||
251 | lblWait->setGeometry( qApp->desktop()->geometry() ); | ||
252 | lblWait->show(); | ||
253 | qApp->processEvents(); | ||
254 | QTimer::singleShot( 1000, lblWait, SLOT(close()) ); | ||
255 | repaint(); | ||
256 | close(); | ||
257 | ServerApplication::allowRestart = TRUE; | ||
258 | } | ||
259 | return; | ||
260 | } | ||
261 | } while ( !settingsTable[currApp].enabled ); | ||
262 | |||
263 | if ( prevApp >= 0 && appLauncher->isRunning(settingsTable[prevApp].app) ) { | ||
264 | qDebug( "Shutdown: %s", settingsTable[prevApp].app ); | ||
265 | QCopEnvelope e(QCString("QPE/Application/") + settingsTable[prevApp].app, | ||
266 | settingsTable[prevApp].stop ); | ||
267 | waitForExit = prevApp; | ||
268 | } else { | ||
269 | qDebug( "Startup: %s", settingsTable[currApp].app ); | ||
270 | QCopEnvelope e(QCString("QPE/Application/") + settingsTable[currApp].app, | ||
271 | settingsTable[currApp].start ); | ||
272 | waitingForLaunch = TRUE; | ||
273 | } | ||
274 | |||
275 | updateButtons(); | ||
276 | } | ||
277 | |||
278 | /* accept current dialog and bring up previous */ | ||
279 | void FirstUse::previousDialog() | ||
280 | { | ||
281 | int prevApp = currApp; | ||
282 | do { | ||
283 | currApp--; | ||
284 | if ( currApp < 0 ) { | ||
285 | currApp = prevApp; | ||
286 | return; | ||
287 | } | ||
288 | } while ( !settingsTable[currApp].enabled ); | ||
289 | |||
290 | if ( prevApp >= 0 ) { | ||
291 | qDebug( "Shutdown: %s", settingsTable[prevApp].app ); | ||
292 | QCopEnvelope e(QCString("QPE/Application/") + settingsTable[prevApp].app, | ||
293 | settingsTable[prevApp].stop ); | ||
294 | /* | ||
295 | if (settingsTable[prevApp].app == QString("systemtime")) | ||
296 | QCopEnvelope e("QPE/Application/citytime", "close()"); | ||
297 | */ | ||
298 | waitForExit = prevApp; | ||
299 | } else { | ||
300 | qDebug( "Startup: %s", settingsTable[currApp].app ); | ||
301 | QCopEnvelope e(QCString("QPE/Application/") + settingsTable[currApp].app, | ||
302 | settingsTable[currApp].start ); | ||
303 | waitingForLaunch = TRUE; | ||
304 | } | ||
305 | |||
306 | updateButtons(); | ||
307 | } | ||
308 | |||
309 | void FirstUse::message(const QCString &msg, const QByteArray &data) | ||
310 | { | ||
311 | QDataStream stream( data, IO_ReadOnly ); | ||
312 | if ( msg == "timeChange(QString)" ) { | ||
313 | QString t; | ||
314 | stream >> t; | ||
315 | if ( t.isNull() ) | ||
316 | unsetenv("TZ"); | ||
317 | else | ||
318 | setenv( "TZ", t.latin1(), 1 ); | ||
319 | } | ||
320 | } | ||
321 | |||
322 | void FirstUse::terminated( int, const QString &app ) | ||
323 | { | ||
324 | qDebug( "--- terminated: %s", app.latin1() ); | ||
325 | if ( waitForExit != -1 && settingsTable[waitForExit].app == app ) { | ||
326 | qDebug( "Startup: %s", settingsTable[currApp].app ); | ||
327 | if ( settingsTable[waitForExit].app == "language" ) { // No tr | ||
328 | Config config("locale"); | ||
329 | config.setGroup( "Language"); | ||
330 | QString l = config.readEntry( "Language", "en"); | ||
331 | if ( l != lang ) { | ||
332 | reloadLanguages(); | ||
333 | needRestart = TRUE; | ||
334 | lang = l; | ||
335 | } | ||
336 | } | ||
337 | QCopEnvelope e(QCString("QPE/Application/") + settingsTable[currApp].app, | ||
338 | settingsTable[currApp].start ); | ||
339 | waitingForLaunch = TRUE; | ||
340 | updateButtons(); | ||
341 | repaint(); | ||
342 | waitForExit = -1; | ||
343 | } else if ( settingsTable[currApp].app == app ) { | ||
344 | nextDialog(); | ||
345 | } else { | ||
346 | back->setEnabled(TRUE); | ||
347 | next->setEnabled(TRUE); | ||
348 | } | ||
349 | } | ||
350 | |||
351 | void FirstUse::newQcopChannel(const QString& channelName) | ||
352 | { | ||
353 | qDebug("channel %s added", channelName.data() ); | ||
354 | QString prefix("QPE/Application/"); | ||
355 | if (channelName.startsWith(prefix)) { | ||
356 | QString appName = channelName.mid(prefix.length()); | ||
357 | if ( currApp >= 0 && appName == settingsTable[currApp].app ) { | ||
358 | qDebug( "Application: %s started", settingsTable[currApp].app ); | ||
359 | waitingForLaunch = FALSE; | ||
360 | updateButtons(); | ||
361 | repaint(); | ||
362 | } else if (appName != "quicklauncher") { | ||
363 | back->setEnabled(FALSE); | ||
364 | next->setEnabled(FALSE); | ||
365 | } | ||
366 | } | ||
367 | } | ||
368 | |||
369 | void FirstUse::reloadLanguages() | ||
370 | { | ||
371 | // read language from config file. Waiting on QCop takes too long. | ||
372 | Config config("locale"); | ||
373 | config.setGroup( "Language"); | ||
374 | QString l = config.readEntry( "Language", "en"); | ||
375 | QString cl = getenv("LANG"); | ||
376 | qWarning("language message - " + l); | ||
377 | // setting anyway... | ||
378 | if (l.isNull() ) | ||
379 | unsetenv( "LANG" ); | ||
380 | else { | ||
381 | qWarning("and its not null"); | ||
382 | setenv( "LANG", l.latin1(), 1 ); | ||
383 | } | ||
384 | #ifndef QT_NO_TRANSLATION | ||
385 | // clear old translators | ||
386 | #ifndef _MSC_VER | ||
387 | //### revise to allow removal of translators under MSVC | ||
388 | if(qApp->translators) { | ||
389 | qApp->translators->setAutoDelete(TRUE); | ||
390 | delete (qApp->translators); | ||
391 | qApp->translators = 0; | ||
392 | } | ||
393 | #endif | ||
394 | |||
395 | // load translation tables | ||
396 | transApp = new QTranslator(qApp); | ||
397 | QString tfn = QPEApplication::qpeDir() + "i18n/"+l+"/qpe.qm"; | ||
398 | qWarning("loading " + tfn); | ||
399 | if ( transApp->load(tfn) ) { | ||
400 | qWarning("installing translator"); | ||
401 | qApp->installTranslator( transApp ); | ||
402 | } else { | ||
403 | delete transApp; | ||
404 | transApp = 0; | ||
405 | } | ||
406 | |||
407 | transLib = new QTranslator(qApp); | ||
408 | tfn = QPEApplication::qpeDir() + "i18n/"+l+"/libqpe.qm"; | ||
409 | qWarning("loading " + tfn); | ||
410 | if ( transLib->load(tfn) ) { | ||
411 | qWarning("installing translator library"); | ||
412 | qApp->installTranslator( transLib ); | ||
413 | } else { | ||
414 | delete transLib; | ||
415 | transLib = 0; | ||
416 | } | ||
417 | loadPixmaps(); | ||
418 | //###language/font hack; should look it up somewhere | ||
419 | #ifdef Q_WS_QWS | ||
420 | if ( l == "ja" || l == "zh_CN" || l == "zh_TW" || l == "ko" ) { | ||
421 | QFont fn = FontManager::unicodeFont( FontManager::Proportional ); | ||
422 | qApp->setFont( fn, TRUE ); | ||
423 | } else { | ||
424 | qApp->setFont( defaultFont, TRUE ); | ||
425 | } | ||
426 | #endif | ||
427 | #endif | ||
428 | } | ||
429 | |||
430 | void FirstUse::paintEvent( QPaintEvent * ) | ||
431 | { | ||
432 | QPainter p( this ); | ||
433 | |||
434 | p.drawPixmap(0,0, splash); | ||
435 | |||
436 | QFont f = p.font(); | ||
437 | f.setPointSize(15); | ||
438 | f.setItalic(FALSE); | ||
439 | f.setBold(FALSE); | ||
440 | p.setFont(f); | ||
441 | |||
442 | if ( currApp < 0 ) { | ||
443 | drawText(p, tr( "Tap anywhere on the screen to continue." )); | ||
444 | } else if ( settingsTable[currApp].app ) { | ||
445 | if ( waitingForLaunch ) | ||
446 | drawText(p, tr("Please wait, loading %1 settings.").arg(tr(settingsTable[currApp].desc)) ); | ||
447 | } else { | ||
448 | drawText(p, tr("Please wait...")); | ||
449 | } | ||
450 | } | ||
451 | |||
452 | void FirstUse::loadPixmaps() | ||
453 | { | ||
454 | /* create background, tr so can change image with language. | ||
455 | images will likely contain text. */ | ||
456 | splash.convertFromImage( Resource::loadImage(tr("FirstUseBackground")) | ||
457 | .smoothScale( width(), height() ) ); | ||
458 | |||
459 | setBackgroundPixmap(splash); | ||
460 | } | ||
461 | |||
462 | void FirstUse::drawText(QPainter &p, const QString &text) | ||
463 | { | ||
464 | QString altered = "<CENTER>" + text + "</CENTER>"; | ||
465 | |||
466 | QSimpleRichText rt(altered, p.font()); | ||
467 | rt.setWidth(width() - 20); | ||
468 | |||
469 | int h = (height() * 3) / 10; // start at 30% | ||
470 | if (rt.height() < height() / 2) | ||
471 | h += ((height() / 2) - rt.height()) / 2; | ||
472 | rt.draw(&p, 10, h, QRegion(0,0, width()-20, height()), palette()); | ||
473 | } | ||
474 | |||
475 | void FirstUse::updateButtons() | ||
476 | { | ||
477 | if ( currApp >= 0 ) { | ||
478 | taskBar->show(); | ||
479 | } | ||
480 | |||
481 | int i = currApp-1; | ||
482 | while ( i >= 0 && !settingsTable[i].enabled ) | ||
483 | i--; | ||
484 | back->setText(tr("<< Back")); | ||
485 | back->setEnabled( i >= 0 && !waitingForLaunch ); | ||
486 | |||
487 | i = currApp+1; | ||
488 | while ( settingsTable[i].app && !settingsTable[i].enabled ) | ||
489 | i++; | ||
490 | if ( !settingsTable[i].app ) | ||
491 | next->setText(tr("Finish")); | ||
492 | else | ||
493 | next->setText(tr("Next >>")); | ||
494 | next->setEnabled( !waitingForLaunch ); | ||
495 | } | ||
496 | |||
497 | void FirstUse::keyPressEvent( QKeyEvent *e ) | ||
498 | { | ||
499 | // Allow cancelling at first dialog, in case display is broken. | ||
500 | if ( e->key() == Key_Escape && currApp < 0 ) | ||
501 | QDialog::keyPressEvent(e); | ||
502 | } | ||
503 | |||
504 | void FirstUse::mouseReleaseEvent( QMouseEvent * ) | ||
505 | { | ||
506 | if ( currApp < 0 ) { | ||
507 | #if defined(QPE_NEED_CALIBRATION) | ||
508 | if ( needCalibrate ) { | ||
509 | releaseMouse(); | ||
510 | Calibrate *cal = new Calibrate; | ||
511 | cal->exec(); | ||
512 | delete cal; | ||
513 | } | ||
514 | #endif | ||
515 | nextDialog(); | ||
516 | } | ||
517 | } | ||