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