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