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