f57cde71e2ff24c4c89a4241aa9ab2c6db31a768
[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 #include <QKeyEvent>
13
14 #include "pirkeysetmetadata.h"
15
16 #include "pirkeysetwidgetitem.h"
17 #include "pirselectkeysetform.h"
18 #include "pirselectdeviceform.h"
19 #include "pirpreferencesform.h"
20 #include "pirdocumentationform.h"
21 #include "piraboutform.h"
22 #include "dialogs/pirtabschoicedialog.h"
23 #include "dialogs/pirfavoritesdialog.h"
24
25 #include "pirkeysetmanager.h"
26 #include "pirpanelmanager.h"
27 #include "macros/pirmacromanager.h"
28
29 //#define DEBUGGING
30 #include <iostream>
31
32 // Some ugly globals used for thread communications:
33
34 // A global to show that a command is being processed:
35 bool commandInFlight = false;
36 QMutex commandIFMutex;
37
38 // The stopRepeatingFlag boolean is the method used to tell running commands
39 // in the worker thread to stop:
40 bool stopRepeatingFlag = false;
41 QMutex stopRepeatingMutex;
42
43
44 extern PIRMakeMgr makeManager;
45
46
47 MainWindow::MainWindow(QWidget *parent)
48   : QMainWindow(parent),
49     ui(new Ui::MainWindow),
50     selectKeysetForm(0),
51     selectDeviceForm(0),
52     preferencesForm(0),
53     documentationForm(0),
54     aboutForm(0),
55     favoritesDialog(0),
56     myKeysets(0),
57     myPanels(0),
58     myMacros(0),
59     currentKeyset(1) // Zero is not a valid keyset any more
60 {
61   ui->setupUi(this);
62
63   // Make this a Maemo 5 stacked widget:
64   setAttribute(Qt::WA_Maemo5StackedWindow);
65
66   // Create the managers:
67   myKeysets = new PIRKeysetManager();
68   myMacros = new PIRMacroManager(this);
69   myPanels = new PIRPanelManager(this);
70
71   // Display the panels:
72   myPanels->updateTabSet();
73
74   // Construct the rest of the forms:
75   selectKeysetForm = new PIRSelectKeysetForm(this);
76   favoritesDialog = new PIRFavoritesDialog(this);
77   myKeysets->populateListWidgets(selectKeysetForm, favoritesDialog);
78   selectKeysetForm->populateKeysetComboBox(myPanels->getKeysetComboBox());
79
80   selectDeviceForm = new PIRSelectDeviceForm(this);
81   PIRKeysetMetaData::populateDevices(selectDeviceForm);
82
83   preferencesForm = new PIRPreferencesForm(this, myKeysets);
84
85   // Retrieve the user's preferences:
86   QSettings settings("pietrzak.org", "Pierogi");
87   if (settings.contains("currentKeysetName"))
88   {
89     myKeysets->findKeysetID(
90       settings.value("currentKeysetMake").toString(),
91       settings.value("currentKeysetName").toString(),
92       currentKeyset);
93   }
94
95   selectKeysetForm->selectKeyset(currentKeyset);
96
97   // Add the corner buttons:
98   insertCornerButtons();
99
100   // Set up all the buttons:
101   enableButtons();
102   myPanels->updateUserButtons();
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   // keyset name -> device name
109   connect(
110     klw,
111     SIGNAL(itemActivated(QListWidgetItem *)),
112     dlw,
113     SLOT(clearSelection()),
114     Qt::QueuedConnection);
115
116   // device name -> keyset name
117   connect(
118     dlw,
119     SIGNAL(itemActivated(QListWidgetItem *)),
120     klw,
121     SLOT(clearSelection()),
122     Qt::QueuedConnection);
123
124 #ifndef DEBUGGING
125   // The PIRModprobe object should take care of setting up and shutting down
126   // the lirc_rx51 kernel module, if necessary:
127  
128   if (modprobeObj.loadRX51Module() != 0)
129   {
130     // Couldn't load module, quit:
131     QMessageBox errBox;
132     errBox.setText("Couldn't load lirc_rx51 kernel module!");
133     errBox.setIcon(QMessageBox::Warning);
134     errBox.exec();
135 //    throw; // Need a clean way to exit here!!!
136   }
137 #endif
138 }
139
140
141 MainWindow::~MainWindow()
142 {
143   if (aboutForm) delete aboutForm;
144   if (documentationForm) delete documentationForm;
145   if (preferencesForm) delete preferencesForm;
146   if (selectDeviceForm) delete selectDeviceForm;
147   if (favoritesDialog) delete favoritesDialog;
148   if (selectKeysetForm) delete selectKeysetForm;
149
150   if (myPanels) delete myPanels;
151   if (myMacros) delete myMacros;
152   if (myKeysets) delete myKeysets;
153   delete ui;
154 }
155
156
157 void MainWindow::setOrientation(ScreenOrientation orientation)
158 {
159 #if defined(Q_OS_SYMBIAN)
160     // If the version of Qt on the device is < 4.7.2, that attribute won't work
161     if (orientation != ScreenOrientationAuto) {
162         const QStringList v = QString::fromAscii(qVersion()).split(QLatin1Char('.'));
163         if (v.count() == 3 && (v.at(0).toInt() << 16 | v.at(1).toInt() << 8 | v.at(2).toInt()) < 0x040702) {
164             qWarning("Screen orientation locking only supported with Qt 4.7.2 and above");
165             return;
166         }
167     }
168 #endif // Q_OS_SYMBIAN
169
170     Qt::WidgetAttribute attribute;
171     switch (orientation) {
172 #if QT_VERSION < 0x040702
173     // Qt < 4.7.2 does not yet have the Qt::WA_*Orientation attributes
174     case ScreenOrientationLockPortrait:
175         attribute = static_cast<Qt::WidgetAttribute>(128);
176         break;
177     case ScreenOrientationLockLandscape:
178         attribute = static_cast<Qt::WidgetAttribute>(129);
179         break;
180     default:
181     case ScreenOrientationAuto:
182         attribute = static_cast<Qt::WidgetAttribute>(130);
183         break;
184 #else // QT_VERSION < 0x040702
185     case ScreenOrientationLockPortrait:
186         attribute = Qt::WA_LockPortraitOrientation;
187         break;
188     case ScreenOrientationLockLandscape:
189         attribute = Qt::WA_LockLandscapeOrientation;
190         break;
191     default:
192     case ScreenOrientationAuto:
193         attribute = Qt::WA_AutoOrientation;
194         break;
195 #endif // QT_VERSION < 0x040702
196     };
197     setAttribute(attribute, true);
198 }
199
200 void MainWindow::showExpanded()
201 {
202 #if defined(Q_OS_SYMBIAN) || defined(Q_WS_SIMULATOR)
203     showFullScreen();
204 #elif defined(Q_WS_MAEMO_5)
205     showMaximized();
206 #else
207     show();
208 #endif
209 }
210
211
212 void MainWindow::enableButtons()
213 {
214   // Just to be sure, check to see if the keyset has been populated:
215   myKeysets->populateKeyset(this, currentKeyset);
216
217   if (preferencesForm)
218   {
219     unsigned int dk = preferencesForm->getDefaultKeyset();
220     if (preferencesForm->defaultControlsVolume() && dk)
221     {
222       myKeysets->populateKeyset(this, dk);
223       myPanels->enableButtons(myKeysets, currentKeyset, dk);
224     }
225     else
226     {
227       myPanels->enableButtons(myKeysets, currentKeyset);
228     }
229   }
230   else
231   {
232     myPanels->enableButtons(myKeysets, currentKeyset);
233   }
234 }
235
236
237 void MainWindow::useMainPanel()
238 {
239   myPanels->useMainPanel();
240 }
241
242
243 void MainWindow::useAltMainPanel()
244 {
245   myPanels->useAltMainPanel();
246 }
247
248
249 QString MainWindow::getCurrentMake()
250 {
251   return makeManager.getMakeString(myKeysets->getMake(currentKeyset));
252 }
253
254
255 QString MainWindow::getCurrentName()
256 {
257   return myKeysets->getDisplayName(currentKeyset);
258 }
259
260
261 QString MainWindow::getCurrentFullName()
262 {
263   return selectKeysetForm->getCurrentKeysetName();
264 }
265
266
267 QString MainWindow::getKeysetMake(
268   unsigned int id)
269 {
270   return makeManager.getMakeString(myKeysets->getMake(id));
271 }
272
273
274 QString MainWindow::getKeysetName(
275   unsigned int id)
276 {
277   return myKeysets->getDisplayName(id);
278 }
279
280
281 QString MainWindow::getFullKeysetName(
282   unsigned int id)
283 {
284   return selectKeysetForm->getKeysetName(id);
285 }
286
287
288 bool MainWindow::findKeysetID(
289   QString make,
290   QString name,
291   unsigned int &id)
292 {
293   return myKeysets->findKeysetID(make, name, id);
294 }
295
296
297 void MainWindow::receivedExternalWarning(
298   const char *warning)
299 {
300   QMessageBox errBox;
301   errBox.setText(warning);
302   errBox.setIcon(QMessageBox::Warning);
303   errBox.exec();
304 }
305
306
307 // Menu actions:
308
309 void MainWindow::on_actionSelectKeyset_triggered()
310 {
311   selectKeysetForm->show();
312 }
313
314 void MainWindow::on_actionBrowse_Device_List_triggered()
315 {
316   selectDeviceForm->show();
317 }
318
319 void MainWindow::on_actionPreferences_triggered()
320 {
321   preferencesForm->show();
322 }
323
324 void MainWindow::on_actionAbout_triggered()
325 {
326   if (!aboutForm)
327   {
328     aboutForm = new PIRAboutForm(this);
329   }
330
331   aboutForm->show();
332 }
333
334 void MainWindow::on_actionDocumentation_triggered()
335 {
336   if (!documentationForm)
337   {
338     documentationForm = new PIRDocumentationForm(this);
339   }
340
341   documentationForm->show();
342 }
343
344
345 // Other actions:
346
347 void MainWindow::keysetSelectionChanged(
348   QListWidgetItem *item)
349 {
350   if (!item) return;  // Should probably display error message here!
351
352   PIRKeysetWidgetItem *kwi = dynamic_cast<PIRKeysetWidgetItem *>(item);
353
354   if (!kwi) return; // Also need to say something here
355
356   if (currentKeyset == kwi->getID())
357   {
358     // We're already on that keyset, so nothing to do:
359     return;
360   }
361
362   // Clean up and remove the current keyset:
363   myKeysets->clearKeyset(currentKeyset);
364   
365   currentKeyset = kwi->getID();
366
367   QSettings settings("pietrzak.org", "Pierogi");
368
369   settings.setValue(
370     "currentKeysetMake",
371     makeManager.getMakeString(kwi->getMake()));
372
373   settings.setValue(
374     "currentKeysetName",
375     myKeysets->getDisplayName(currentKeyset));
376
377   enableButtons();
378 }
379
380
381 void MainWindow::finalCleanup()
382 {
383   // Perform any necessary cleanup work here.
384
385   // Make certain that the thread stops repeating:
386   stopRepeating();
387 }
388
389
390 void MainWindow::addToFavorites(
391   PIRKeysetWidgetItem *kwi)
392 {
393   //Add keyset to the favorites:
394   favoritesDialog->addItem(new PIRKeysetWidgetItem(kwi));
395
396   // And, add the keyset id to the persistent list:
397   QSettings settings("pietrzak.org", "Pierogi");
398
399   int favSettingsSize = settings.beginReadArray("favorites");
400   settings.endArray();
401
402   settings.beginWriteArray("favorites");
403   settings.setArrayIndex(favSettingsSize);
404
405   settings.setValue(
406     "keysetMake",
407     makeManager.getMakeString(kwi->getMake()));
408
409   settings.setValue("keysetName", kwi->getInternalName());
410
411   settings.endArray();
412 }
413
414
415 void MainWindow::removeFromFavorites(
416   unsigned int keysetID)
417 {
418   favoritesDialog->removeItem(keysetID);
419
420   // Remove this item from the persistent list.  Well, actually, it seems a
421   // little more convenient to just blow away the existing list of favorites
422   // and rewrite it, as modifying an existing QSettings array in the middle
423   // seems a bit hard...
424   QSettings settings("pietrzak.org", "Pierogi");
425
426   settings.remove("favorites");
427
428   int count = favoritesDialog->getCount();
429
430   // If the count is empty, we can stop right here:
431   if (count == 0) return;
432
433   int index = 0;
434   unsigned int id;
435   PIRKeysetWidgetItem *kwi = NULL;
436   settings.beginWriteArray("favorites");
437   while (index < count)
438   {
439     kwi = favoritesDialog->getItem(index);
440
441     settings.setArrayIndex(index);
442     id = kwi->getID();
443
444     settings.setValue(
445       "keysetMake",
446       makeManager.getMakeString(myKeysets->getMake(id)));
447
448     settings.setValue("keysetName", myKeysets->getDisplayName(id));
449
450     ++index;
451   }
452   settings.endArray();
453 }
454
455
456 /*
457 void MainWindow::populateFavorites()
458 {
459   QSettings settings("pietrzak.org", "Pierogi");
460
461   int size = settings.beginReadArray("favorites");
462   int index = 0;
463   QString make;
464   QString name;
465   PIRKeysetWidgetItem *kwi;
466
467   while (index < size)
468   {
469     settings.setArrayIndex(index);
470     make = settings.value("keysetMake").toString();
471     name = settings.value("keysetName").toString();
472
473     kwi = myKeysets->makeKeysetItem(make, name);
474
475     // Did the item creation work?
476     if (kwi)
477     {
478       // Keyset does exist, so continue:
479       favoritesDialog->addItem(kwi);
480     }
481
482     ++index;
483   }
484
485   settings.endArray();
486 }
487 */
488
489
490 bool MainWindow::startRepeating(
491   PIRKeyName name)
492 {
493   QMutexLocker locker(&commandIFMutex);
494   if (!commandInFlight)
495   {
496     commandInFlight = true;
497     emit buttonPressed(currentKeyset, name);
498     return true;
499   }
500   else
501   {
502     return false;
503   }
504 }
505
506
507 bool MainWindow::startRepeating(
508   PIRKeyName name,
509   unsigned int keysetID)
510 {
511   QMutexLocker locker(&commandIFMutex);
512   if (!commandInFlight)
513   {
514     commandInFlight = true;
515     emit buttonPressed(keysetID, name);
516     return true;
517   }
518   else
519   {
520     return false;
521   }
522 }
523
524
525 void MainWindow::stopRepeating()
526 {
527   QMutexLocker locker(&stopRepeatingMutex);
528   stopRepeatingFlag = true;
529 }
530
531
532 void MainWindow::selectPrevFavKeyset()
533 {
534   favoritesDialog->selectPrevFavKeyset();
535 }
536
537
538 void MainWindow::selectNextFavKeyset()
539 {
540   favoritesDialog->selectNextFavKeyset();
541 }
542
543
544 void MainWindow::insertCornerButtons()
545 {
546   // Set up the dialog boxes:
547   PIRTabsChoiceDialog *tcd = new PIRTabsChoiceDialog(this);
548 //  favoritesDialog = new PIRFavoritesDialog(this);
549
550   // Next, set up the corner buttons:
551   QPushButton *button =
552     new QPushButton(QIcon(":/icons/folder_plus_icon&32.png"), "");
553
554   button->setFlat(true);
555
556   connect(
557     button,
558     SIGNAL(clicked()),
559     tcd,
560     SLOT(exec()),
561     Qt::QueuedConnection);
562
563   ui->mainTabWidget->setCornerWidget(button, Qt::TopRightCorner);
564
565   button =
566     new QPushButton(QIcon(":/icons/align_just_icon&32.png"), "");
567
568   button->setFlat(true);
569
570   connect(
571     button,
572     SIGNAL(clicked()),
573     favoritesDialog,
574     SLOT(exec()),
575     Qt::QueuedConnection);
576
577   ui->mainTabWidget->setCornerWidget(button, Qt::TopLeftCorner);
578 }
579
580
581 void MainWindow::disableUpdates()
582 {
583   ui->mainTabWidget->setUpdatesEnabled(false);
584 }
585
586
587 void MainWindow::enableUpdates()
588 {
589   ui->mainTabWidget->setUpdatesEnabled(true);
590 }
591
592
593 void MainWindow::clearTabs()
594 {
595   ui->mainTabWidget->clear();
596 }
597
598
599 void MainWindow::addTab(
600   QWidget *page,
601   QString label)
602 {
603   ui->mainTabWidget->addTab(page, label);
604 }
605
606 void MainWindow::setupTabs(
607   PIRTabBarName name)
608 {
609   myPanels->setupTabs(name);
610 }
611
612
613 bool MainWindow::selectNextKeyset()
614 {
615   return selectKeysetForm->selectNextKeyset();
616 }
617
618
619 bool MainWindow::selectPrevKeyset()
620 {
621   return selectKeysetForm->selectPrevKeyset();
622 }
623
624
625 bool MainWindow::selectFirstKeyset()
626 {
627   return selectKeysetForm->selectFirstKeyset();
628 }
629
630
631 void MainWindow::openCurrentKeysetDialog()
632 {
633   selectKeysetForm->openCurrentKeysetDialog();
634 }
635
636
637 void MainWindow::updateKeysetSelection(
638   unsigned int targetID)
639 {
640   selectKeysetForm->selectKeyset(targetID);
641 }
642
643
644 PIRMacroPack *MainWindow::getUserPack()
645 {
646   return myMacros->getUserPack();
647 }
648
649
650 PIRMacroPack *MainWindow::getMultitapPack()
651 {
652   return myMacros->getMultitapPack();
653 }
654
655
656 void MainWindow::keyPressEvent(
657   QKeyEvent *event)
658 {
659   switch(event->key())
660   {
661   case Qt::Key_A:
662     myMacros->handleKeypress('A');
663     break;
664   case Qt::Key_B:
665     myMacros->handleKeypress('B');
666     break;
667   case Qt::Key_C:
668     myMacros->handleKeypress('C');
669     break;
670   case Qt::Key_D:
671     myMacros->handleKeypress('D');
672     break;
673   case Qt::Key_E:
674     myMacros->handleKeypress('E');
675     break;
676   case Qt::Key_F:
677     myMacros->handleKeypress('F');
678     break;
679   case Qt::Key_G:
680     myMacros->handleKeypress('G');
681     break;
682   case Qt::Key_H:
683     myMacros->handleKeypress('H');
684     break;
685   case Qt::Key_I:
686     myMacros->handleKeypress('I');
687     break;
688   case Qt::Key_J:
689     myMacros->handleKeypress('J');
690     break;
691   case Qt::Key_K:
692     myMacros->handleKeypress('K');
693     break;
694   case Qt::Key_L:
695     myMacros->handleKeypress('L');
696     break;
697   case Qt::Key_M:
698     myMacros->handleKeypress('M');
699     break;
700   case Qt::Key_N:
701     myMacros->handleKeypress('N');
702     break;
703   case Qt::Key_O:
704     myMacros->handleKeypress('O');
705     break;
706   case Qt::Key_P:
707     myMacros->handleKeypress('P');
708     break;
709   case Qt::Key_Q:
710     myMacros->handleKeypress('Q');
711     break;
712   case Qt::Key_R:
713     myMacros->handleKeypress('R');
714     break;
715   case Qt::Key_S:
716     myMacros->handleKeypress('S');
717     break;
718   case Qt::Key_T:
719     myMacros->handleKeypress('T');
720     break;
721   case Qt::Key_U:
722     myMacros->handleKeypress('U');
723     break;
724   case Qt::Key_V:
725     myMacros->handleKeypress('V');
726     break;
727   case Qt::Key_W:
728     myMacros->handleKeypress('W');
729     break;
730   case Qt::Key_X:
731     myMacros->handleKeypress('X');
732     break;
733   case Qt::Key_Y:
734     myMacros->handleKeypress('Y');
735     break;
736   case Qt::Key_Z:
737     myMacros->handleKeypress('Z');
738     break;
739   case Qt::Key_Space:
740     myMacros->handleKeypress(' ');
741     break;
742   default:
743     QMainWindow::keyPressEvent(event);
744     break;
745   }
746 }
747
748
749 bool MainWindow::hasMacroButton(
750   unsigned int buttonID)
751 {
752   return myMacros->hasMacroButton(buttonID);
753 }
754
755
756 QString MainWindow::getMacroButtonText(
757   unsigned int buttonID)
758 {
759   return myMacros->getMacroButtonText(buttonID);
760 }
761
762
763 void MainWindow::executeMacroButton(
764   unsigned int buttonID)
765 {
766   myMacros->executeMacroButton(buttonID);
767 }
768
769
770 void MainWindow::updateUserButtons()
771 {
772   myPanels->updateUserButtons();
773 }
774
775
776 void MainWindow::storeMacros()
777 {
778   myMacros->storeSettings();
779 }
780
781
782 void MainWindow::setMacroKbdFocus(
783   int index)
784 {
785   myMacros->setKbdFocus(index);
786 }
787
788
789 void MainWindow::setMacroBtnFocus(
790   int index)
791 {
792   myMacros->setBtnFocus(index);
793 }