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