Change back to real tabbed window, updates keysets
[pierogi] / mainwindow.cpp
1 #include "mainwindow.h"
2 #include "ui_mainwindow.h"
3
4 #include <QtCore/QCoreApplication>
5 #include <QMutex>
6 #include <QtGui/QMessageBox>
7 #include <QPushButton>
8 #include <QDialog>
9 #include <QDialogButtonBox>
10 #include <QScrollArea>
11 #include <QSettings>
12
13 #include "pirkeysetmetadata.h"
14
15 #include "pirkeysetwidgetitem.h"
16 #include "pirselectkeysetform.h"
17 #include "pirselectdeviceform.h"
18 #include "pirpreferencesform.h"
19 #include "pirdocumentationform.h"
20 #include "piraboutform.h"
21 #include "dialogs/pirtabschoicedialog.h"
22
23 #include "pirkeysetmanager.h"
24 #include "pirpanelmanager.h"
25
26 //#define DEBUGGING
27 //#include <iostream>
28
29 // Some ugly globals used for thread communications:
30
31 // A global to show that a command is being processed:
32 bool commandInFlight = false;
33 QMutex commandIFMutex;
34
35 // The stopRepeatingFlag boolean is the method used to tell running commands
36 // in the worker thread to stop:
37 bool stopRepeatingFlag = false;
38 QMutex stopRepeatingMutex;
39
40
41 extern PIRMakeMgr makeManager;
42
43
44 MainWindow::MainWindow(QWidget *parent)
45   : QMainWindow(parent),
46     ui(new Ui::MainWindow),
47     selectKeysetForm(0),
48     selectDeviceForm(0),
49     preferencesForm(0),
50     documentationForm(0),
51     aboutForm(0),
52     myKeysets(0),
53     myPanels(0),
54     currentKeyset(1) // Zero is not a valid keyset any more
55 {
56   ui->setupUi(this);
57
58   // Make this a Maemo 5 stacked widget:
59   setAttribute(Qt::WA_Maemo5StackedWindow);
60
61   // Create the managers:
62   myKeysets = new PIRKeysetManager();
63   myPanels = new PIRPanelManager(this);
64
65   // Display the panels:
66   myPanels->updateTabSet();
67
68   // Add the corner button:
69   insertCornerButton();
70
71   // Construct the rest of the forms:
72   selectKeysetForm = new PIRSelectKeysetForm(this);
73   myKeysets->populateSelectionWidget(selectKeysetForm);
74
75   selectDeviceForm = new PIRSelectDeviceForm(this);
76   PIRKeysetMetaData::populateDevices(selectDeviceForm);
77
78   preferencesForm = new PIRPreferencesForm(this, myKeysets);
79
80   // Remember any favorites the user has already set:
81   populateFavorites();
82
83   // Retrieve the user's preferences:
84   QSettings settings("pietrzak.org", "Pierogi");
85   if (settings.contains("currentKeysetName"))
86   {
87     myKeysets->findKeysetID(
88       settings.value("currentKeysetMake").toString(),
89       settings.value("currentKeysetName").toString(),
90       currentKeyset);
91   }
92
93   enableButtons();
94
95   QListWidget *fkw = myPanels->getFavoritesListWidget();
96
97   connect(
98     fkw,
99     SIGNAL(itemActivated(QListWidgetItem *)),
100     this,
101     SLOT(keysetSelectionChanged(QListWidgetItem *)),
102     Qt::QueuedConnection);
103
104   // Make sure the three selection lists don't show different selections:
105   QListWidget *klw = selectKeysetForm->getKeysetListWidget();
106   QListWidget *dlw = selectDeviceForm->getDeviceListWidget();
107
108   // favorites -> keyset name
109   connect(
110     fkw,
111     SIGNAL(itemActivated(QListWidgetItem *)),
112     klw,
113     SLOT(clearSelection()),
114     Qt::QueuedConnection);
115
116   // favorites -> device name
117   connect(
118     fkw,
119     SIGNAL(itemActivated(QListWidgetItem *)),
120     dlw,
121     SLOT(clearSelection()),
122     Qt::QueuedConnection);
123
124   // keyset name -> favorites
125   connect(
126     klw,
127     SIGNAL(itemActivated(QListWidgetItem *)),
128     fkw,
129     SLOT(clearSelection()),
130     Qt::QueuedConnection);
131
132   // device name -> favorites
133   connect(
134     dlw,
135     SIGNAL(itemActivated(QListWidgetItem *)),
136     fkw,
137     SLOT(clearSelection()),
138     Qt::QueuedConnection);
139
140   // keyset name -> device name
141   connect(
142     klw,
143     SIGNAL(itemActivated(QListWidgetItem *)),
144     dlw,
145     SLOT(clearSelection()),
146     Qt::QueuedConnection);
147
148   // device name -> keyset name
149   connect(
150     dlw,
151     SIGNAL(itemActivated(QListWidgetItem *)),
152     klw,
153     SLOT(clearSelection()),
154     Qt::QueuedConnection);
155
156 #ifndef DEBUGGING
157   // The PIRModprobe object should take care of setting up and shutting down
158   // the lirc_rx51 kernel module, if necessary:
159  
160   if (modprobeObj.loadRX51Module() != 0)
161   {
162     // Couldn't load module, quit:
163     QMessageBox errBox;
164     errBox.setText("Couldn't load lirc_rx51 kernel module!");
165     errBox.setIcon(QMessageBox::Warning);
166     errBox.exec();
167 //    throw; // Need a clean way to exit here!!!
168   }
169 #endif
170 }
171
172
173 MainWindow::~MainWindow()
174 {
175   delete myKeysets;
176   if (selectKeysetForm) delete selectKeysetForm;
177   if (selectDeviceForm) delete selectDeviceForm;
178 //  if (panelSelectionForm) delete panelSelectionForm;
179   if (documentationForm) delete documentationForm;
180   if (aboutForm) delete aboutForm;
181   delete ui;
182 }
183
184
185 void MainWindow::setOrientation(ScreenOrientation orientation)
186 {
187 #if defined(Q_OS_SYMBIAN)
188     // If the version of Qt on the device is < 4.7.2, that attribute won't work
189     if (orientation != ScreenOrientationAuto) {
190         const QStringList v = QString::fromAscii(qVersion()).split(QLatin1Char('.'));
191         if (v.count() == 3 && (v.at(0).toInt() << 16 | v.at(1).toInt() << 8 | v.at(2).toInt()) < 0x040702) {
192             qWarning("Screen orientation locking only supported with Qt 4.7.2 and above");
193             return;
194         }
195     }
196 #endif // Q_OS_SYMBIAN
197
198     Qt::WidgetAttribute attribute;
199     switch (orientation) {
200 #if QT_VERSION < 0x040702
201     // Qt < 4.7.2 does not yet have the Qt::WA_*Orientation attributes
202     case ScreenOrientationLockPortrait:
203         attribute = static_cast<Qt::WidgetAttribute>(128);
204         break;
205     case ScreenOrientationLockLandscape:
206         attribute = static_cast<Qt::WidgetAttribute>(129);
207         break;
208     default:
209     case ScreenOrientationAuto:
210         attribute = static_cast<Qt::WidgetAttribute>(130);
211         break;
212 #else // QT_VERSION < 0x040702
213     case ScreenOrientationLockPortrait:
214         attribute = Qt::WA_LockPortraitOrientation;
215         break;
216     case ScreenOrientationLockLandscape:
217         attribute = Qt::WA_LockLandscapeOrientation;
218         break;
219     default:
220     case ScreenOrientationAuto:
221         attribute = Qt::WA_AutoOrientation;
222         break;
223 #endif // QT_VERSION < 0x040702
224     };
225     setAttribute(attribute, true);
226 }
227
228 void MainWindow::showExpanded()
229 {
230 #if defined(Q_OS_SYMBIAN) || defined(Q_WS_SIMULATOR)
231     showFullScreen();
232 #elif defined(Q_WS_MAEMO_5)
233     showMaximized();
234 #else
235     show();
236 #endif
237 }
238
239
240 void MainWindow::enableButtons()
241 {
242   // Just to be sure, check to see if the keyset has been populated:
243   myKeysets->populateKeyset(this, currentKeyset);
244
245   if (preferencesForm)
246   {
247     unsigned int dk = preferencesForm->getDefaultKeyset();
248     if (preferencesForm->defaultControlsVolume() && dk)
249     {
250       myKeysets->populateKeyset(this, dk);
251       myPanels->enableButtons(myKeysets, currentKeyset, dk);
252     }
253     else
254     {
255       myPanels->enableButtons(myKeysets, currentKeyset);
256     }
257   }
258   else
259   {
260     myPanels->enableButtons(myKeysets, currentKeyset);
261   }
262 }
263
264
265 void MainWindow::useMainPanel()
266 {
267   myPanels->useMainPanel();
268 }
269
270
271 void MainWindow::useAltMainPanel()
272 {
273   myPanels->useAltMainPanel();
274 }
275
276
277 QString MainWindow::getCurrentMake()
278 {
279   return makeManager.getMakeString(myKeysets->getMake(currentKeyset));
280 }
281
282
283 QString MainWindow::getCurrentName()
284 {
285   return myKeysets->getDisplayName(currentKeyset);
286 }
287
288
289 void MainWindow::receivedExternalWarning(
290   const char *warning)
291 {
292   QMessageBox errBox;
293   errBox.setText(warning);
294   errBox.setIcon(QMessageBox::Warning);
295   errBox.exec();
296 }
297
298
299 // Menu actions:
300
301 void MainWindow::on_actionSelectKeyset_triggered()
302 {
303   selectKeysetForm->show();
304 }
305
306 void MainWindow::on_actionSelect_Device_By_Name_triggered()
307 {
308   selectDeviceForm->show();
309 }
310
311 void MainWindow::on_actionPreferences_triggered()
312 {
313   preferencesForm->show();
314 }
315
316 void MainWindow::on_actionAbout_triggered()
317 {
318   if (!aboutForm)
319   {
320     aboutForm = new PIRAboutForm(this);
321   }
322
323   aboutForm->show();
324 }
325
326 void MainWindow::on_actionDocumentation_triggered()
327 {
328   if (!documentationForm)
329   {
330     documentationForm = new PIRDocumentationForm(this);
331   }
332
333   documentationForm->show();
334 }
335
336
337 // Other actions:
338
339 void MainWindow::keysetSelectionChanged(
340   QListWidgetItem *item)
341 {
342   if (!item) return;  // Should probably display error message here!
343
344   PIRKeysetWidgetItem *kwi = dynamic_cast<PIRKeysetWidgetItem *>(item);
345
346   if (!kwi) return; // Also need to say something here
347
348   if (currentKeyset == kwi->getID())
349   {
350     // We're already on that keyset, so nothing to do:
351     return;
352   }
353   
354   currentKeyset = kwi->getID();
355
356   QSettings settings("pietrzak.org", "Pierogi");
357
358   settings.setValue(
359     "currentKeysetMake",
360     makeManager.getMakeString(kwi->getMake()));
361
362   settings.setValue(
363     "currentKeysetName",
364     myKeysets->getDisplayName(currentKeyset));
365
366   enableButtons();
367 }
368
369
370 void MainWindow::finalCleanup()
371 {
372   // Perform any necessary cleanup work here.
373
374   // Make certain that the thread stops repeating:
375   stopRepeating();
376 }
377
378
379 void MainWindow::addCurrentKeyset(
380   QListWidget *qlw)
381 {
382   // Is the current keyset already a favorite?
383   int count = qlw->count();
384   int index = 0;
385   PIRKeysetWidgetItem *kwi = NULL;
386   while (index < count)
387   {
388     kwi = dynamic_cast<PIRKeysetWidgetItem *>(
389       qlw->item(index));
390
391     if (kwi && (kwi->getID() == currentKeyset))
392     {
393       // Current keyset already in list!  No need to continue.
394       return;
395     }
396     ++index;
397   }
398
399   // Ok, add the current keyset to the favorites:
400   PIRMakeName make = myKeysets->getMake(currentKeyset);
401
402   QString name = makeManager.getMakeString(make);
403   name.append(" ");
404   name.append(myKeysets->getDisplayName(currentKeyset));
405
406   qlw->addItem(new PIRKeysetWidgetItem(name, currentKeyset, make));
407
408   // And, add the keyset id to the persistent list:
409   QSettings settings("pietrzak.org", "Pierogi");
410
411   int favSettingsSize = settings.beginReadArray("favorites");
412   settings.endArray();
413
414   settings.beginWriteArray("favorites");
415   settings.setArrayIndex(favSettingsSize);
416
417   settings.setValue(
418     "keysetMake",
419     makeManager.getMakeString(myKeysets->getMake(currentKeyset)));
420
421   settings.setValue("keysetName", myKeysets->getDisplayName(currentKeyset));
422
423   settings.endArray();
424 }
425
426
427 void MainWindow::removeFavoriteKeyset(
428   QListWidget *qlw)
429 {
430   // Deleting an item removes it from the list, so just grab the currently
431   // selected item and delete it:
432   QListWidgetItem *item = qlw->currentItem();
433
434   if (item) delete item;
435
436   // Remove this item from the persistent list.  Well, actually, it seems a
437   // little more convenient to just blow away the existing list of favorites
438   // and rewrite it, as modifying an existing QSettings array in the middle
439   // seems a bit hard...
440   QSettings settings("pietrzak.org", "Pierogi");
441
442   settings.remove("favorites");
443
444   int count = qlw->count();
445
446   // If the count is empty, we can stop right here:
447   if (count == 0) return;
448
449   int index = 0;
450   unsigned int id;
451   PIRKeysetWidgetItem *kwi = NULL;
452   settings.beginWriteArray("favorites");
453   while (index < count)
454   {
455     kwi = dynamic_cast<PIRKeysetWidgetItem *>(qlw->item(index));
456
457     settings.setArrayIndex(index);
458     id = kwi->getID();
459
460     settings.setValue(
461       "keysetMake",
462       makeManager.getMakeString(myKeysets->getMake(id)));
463
464     settings.setValue("keysetName", myKeysets->getDisplayName(id));
465
466     ++index;
467   }
468   settings.endArray();
469 }
470
471
472 void MainWindow::populateFavorites()
473 {
474   QSettings settings("pietrzak.org", "Pierogi");
475
476   int size = settings.beginReadArray("favorites");
477   int index = 0;
478   QString make;
479   QString name;
480   PIRKeysetWidgetItem *kwi;
481
482   while (index < size)
483   {
484     settings.setArrayIndex(index);
485     make = settings.value("keysetMake").toString();
486     name = settings.value("keysetName").toString();
487
488     kwi = myKeysets->makeKeysetItem(make, name);
489
490     // Did the item creation work?
491     if (kwi)
492     {
493       // Keyset does exist, so continue:
494       myPanels->addFavoritesItem(kwi);
495     }
496
497     ++index;
498   }
499
500   settings.endArray();
501 }
502
503
504 void MainWindow::startRepeating(
505   PIRKeyName name)
506 {
507   QMutexLocker locker(&commandIFMutex);
508   if (!commandInFlight)
509   {
510     commandInFlight = true;
511     emit buttonPressed(currentKeyset, name);
512   }
513 }
514
515
516 void MainWindow::startRepeating(
517   PIRKeyName name,
518   unsigned int keysetID)
519 {
520   QMutexLocker locker(&commandIFMutex);
521   if (!commandInFlight)
522   {
523     commandInFlight = true;
524     emit buttonPressed(keysetID, name);
525   }
526 }
527
528
529 void MainWindow::stopRepeating()
530 {
531   QMutexLocker locker(&stopRepeatingMutex);
532   stopRepeatingFlag = true;
533 }
534
535
536 void MainWindow::selectPrevFavKeyset()
537 {
538   myPanels->selectPrevFavKeyset();
539 }
540
541
542 void MainWindow::selectNextFavKeyset()
543 {
544   myPanels->selectNextFavKeyset();
545 }
546
547
548 void MainWindow::insertCornerButton()
549 {
550   // Set up the dialog box:
551   PIRTabsChoiceDialog *tcd = new PIRTabsChoiceDialog(this);
552
553   // Next, set up the corner button itself:
554   QPushButton *button =
555     new QPushButton(QIcon(":/icons/align_just_icon&32.png"), "");
556
557   button->setFlat(true);
558
559   connect(
560     button,
561     SIGNAL(clicked()),
562     tcd,
563     SLOT(exec()),
564     Qt::QueuedConnection);
565
566   ui->mainTabWidget->setCornerWidget(button);
567 }
568
569
570 void MainWindow::disableUpdates()
571 {
572   ui->mainTabWidget->setUpdatesEnabled(false);
573 }
574
575
576 void MainWindow::enableUpdates()
577 {
578   ui->mainTabWidget->setUpdatesEnabled(true);
579 }
580
581
582 void MainWindow::clearTabs()
583 {
584   ui->mainTabWidget->clear();
585 }
586
587
588 void MainWindow::addTab(
589   QWidget *page,
590   QString label)
591 {
592   ui->mainTabWidget->addTab(page, label);
593 }
594
595 void MainWindow::setupTabs(
596   PIRTabBarName name)
597 {
598   myPanels->setupTabs(name);
599 }