Major new release: Several events can now be defined and one can set events to occur...
authorChristophe Dumez <dchris@gmail.com>
Sat, 10 Jul 2010 15:53:32 +0000 (17:53 +0200)
committerChristophe Dumez <dchris@gmail.com>
Sat, 10 Jul 2010 15:53:32 +0000 (17:53 +0200)
20 files changed:
Changelog
TimedSilencer.pro
TimedSilencer.pro.user
alarmd_backend.h
checklistdelegate.cpp [new file with mode: 0644]
checklistdelegate.h [new file with mode: 0644]
eventlistdelegate.cpp [new file with mode: 0644]
eventlistdelegate.h [new file with mode: 0644]
main.cpp
mainwindow.cpp
mainwindow.h
newalarmdlg.cpp [new file with mode: 0644]
newalarmdlg.h [new file with mode: 0644]
profileevent.h [new file with mode: 0644]
qmaemo5weekdayspickselector.cpp [new file with mode: 0644]
qmaemo5weekdayspickselector.h [new file with mode: 0644]
qmaemo5weekdayspickwidget.cpp [new file with mode: 0644]
qmaemo5weekdayspickwidget.h [new file with mode: 0644]
switchingeventlist.cpp [new file with mode: 0644]
switchingeventlist.h [new file with mode: 0644]

index 5a4ed5a..52ddda4 100644 (file)
--- a/Changelog
+++ b/Changelog
@@ -1,3 +1,8 @@
+* Unreleased - Christophe Dumez <dchris@gmail.com> - v0.6
+    - Entirely new UI
+    - Several profile switching events can now be set
+    - Events can be defined for given days only
+
 * Mon Jul 7 2010 - Christophe Dumez <dchris@gmail.com> - v0.5
     - Make sure settings are only saved when the "Save" button is pressed
     - Daily profile switching is now deactivated as a default
index c7b33e3..9b76a78 100644 (file)
@@ -16,12 +16,25 @@ TEMPLATE = app
 
 
 SOURCES += main.cpp\
-           mainwindow.cpp
+           mainwindow.cpp \
+    newalarmdlg.cpp \
+    switchingeventlist.cpp \
+    qmaemo5weekdayspickselector.cpp \
+    qmaemo5weekdayspickwidget.cpp \
+    checklistdelegate.cpp \
+    eventlistdelegate.cpp
 
 HEADERS  += mainwindow.h \
             alarmd_backend.h \
             dbus_backend.h \
-            phone_profile.h
+            phone_profile.h \
+    newalarmdlg.h \
+    switchingeventlist.h \
+    qmaemo5weekdayspickselector.h \
+    qmaemo5weekdayspickwidget.h \
+    checklistdelegate.h \
+    profileevent.h \
+    eventlistdelegate.h
 
 # Translations
 TRANSLATIONS = $$LANG_PATH/timedsilencer_en.ts \
@@ -30,7 +43,7 @@ TRANSLATIONS = $$LANG_PATH/timedsilencer_en.ts \
 
 RESOURCES = lang.qrc
 
-DEFINES += QT_NO_DEBUG_OUTPUT
+#DEFINES += QT_NO_DEBUG_OUTPUT
 
 # INSTALL
 unix {
@@ -64,4 +77,3 @@ unix {
   icon64.path = $$DATADIR/icons/hicolor/64x64/apps
   icon64.files += ico/64x64/$${TARGET}.png
 }
-
index 8f553ad..0a399d8 100644 (file)
     <value key="Qt4ProjectManager.MaemoRunConfiguration.DeviceId" type="qulonglong">16</value>
     <valuemap key="Qt4ProjectManager.MaemoRunConfiguration.LastDeployed" type="QVariantMap">
      <value key="192.168.1.4" type="QDateTime">2010-06-29T00:09:20</value>
-     <value key="localhost" type="QDateTime">2010-07-07T09:57:55</value>
+     <value key="localhost" type="QDateTime">2010-07-10T17:45:09</value>
     </valuemap>
    </valuemap>
    <value key="ProjectExplorer.Target.RunConfigurationCount" type="int">1</value>
index 68b7fe9..8d8746b 100644 (file)
 #include <QTime>
 #include <QString>
 #include <QSettings>
+#include <QPair>
 #include <alarmd/libalarm.h>
 #include <dbus-1.0/dbus/dbus-protocol.h>
 #include <time.h>
 
 #include "phone_profile.h"
+#include "dbus_backend.h"
+#include "profileevent.h"
 
 // Alarmd documentation found at:
 // http://wiki.maemo.org/Documentation/Maemo_5_Developer_Guide/Using_Generic_Platform_Components/Alarm_Framework
@@ -42,45 +45,117 @@ private:
     return (time_t) time(0) + time_diff;
   }
 
+  static uint32_t daysToMask(QList<int> days) {
+    uint32_t mask = 0;
+    foreach(const int& d, days) {
+      switch(d) {
+      case MON:
+        mask |= ALARM_RECUR_WDAY_MON;
+        break;
+      case TUE:
+        mask |= ALARM_RECUR_WDAY_TUE;
+        break;
+      case WED:
+        mask |= ALARM_RECUR_WDAY_WED;
+        break;
+      case THU:
+        mask |= ALARM_RECUR_WDAY_THU;
+        break;
+      case FRI:
+        mask |= ALARM_RECUR_WDAY_FRI;
+        break;
+      case SAT:
+        mask |= ALARM_RECUR_WDAY_SAT;
+        break;
+      case SUN:
+        mask |= ALARM_RECUR_WDAY_SUN;
+        break;
+      default:
+        Q_ASSERT(0); // Should never go here
+        mask |= ALARM_RECUR_WDAY_ALL;
+        break;
+      }
+    }
+    return mask;
+  }
+
 public:
-  static void deleteEvents() {
-    // Get events cookies
+  // Is only called on program uninstall
+  static void deleteAllEvents() {
     QSettings settings("TimedSilencer", "TimedSilencer");
-    const cookie_t silent_cookie = settings.value("silencing_cookie", 0).toLongLong();
-    if(silent_cookie != 0) {
-      qDebug("Deleting silent profile event with cookie %ld", (long) silent_cookie);
-      alarmd_event_del(silent_cookie);
+    QHash<QString, QVariant> events = settings.value("events").toHash();
+    foreach(QVariant var_ev, events) {
+      ProfileEvent *pe = ProfileEvent::load(var_ev);
+      foreach(const long &cookie, pe->alarmd_cookies) {
+        qDebug("Unregistering event with cookie %ld", cookie);
+        alarmd_event_del(cookie);
+      }
+      delete pe;
     }
-    const cookie_t general_cookie = settings.value("unsilencing_cookie", 0).toLongLong();
-    if(general_cookie != 0) {
-      qDebug("Deleting general profile event with cookie %ld", (long) general_cookie);
-      alarmd_event_del(general_cookie);
+    // Save in QSettings
+    events.clear();
+    settings.setValue("events", events);
+  }
+
+  static void deleteEvents(QByteArray event_id) {
+    deleteEvents(ProfileEvent::findByID(event_id));
+  }
+
+  static void deleteEvents(ProfileEvent *pe) {
+    // unregistering events
+    foreach(const long &cookie, pe->alarmd_cookies) {
+      qDebug("Unregistering event with cookie %ld", cookie);
+      alarmd_event_del(cookie);
     }
+    pe->alarmd_cookies.clear();
+    ProfileEvent::clearCookies(pe->getID());
   }
 
-  static void setProfileEvent(Profile p, const QTime &event_time) {
-    // Get event cookie
-    QSettings settings("TimedSilencer", "TimedSilencer");
-    cookie_t cookie;
-    if(p == SILENT)
-      cookie = settings.value("silencing_cookie", 0).toLongLong();
-    else
-      cookie = settings.value("unsilencing_cookie", 0).toLongLong();
-    alarm_event_t *eve = 0;
-    if(cookie == 0 || (eve = alarmd_event_get(cookie)) == 0) {
-      qDebug("Profile event does not exist yet, creating it...");
-      // The event does not exist yet
-      newProfileEvent(p, event_time);
-      return;
+  static void setProfileEvents(QByteArray event_id) {
+    setProfileEvents(ProfileEvent::findByID(event_id));
+  }
+
+  static bool checkIfStillActive(ProfileEvent *pe) {
+    Q_ASSERT(pe->activated);
+    foreach(const long &cookie, pe->alarmd_cookies) {
+      alarm_event_t *eve = 0;
+      if((eve = alarmd_event_get(cookie)) != 0) {
+        // Free all dynamic memory associated with the alarm event
+        alarm_event_delete(eve);
+        return true;
+      }
+    }
+    return false;
+  }
+
+  static void setProfileEvents(ProfileEvent *pe) {
+    Q_ASSERT(pe->activated);
+    // First clear old alarmd events
+    foreach(const long &cookie, pe->alarmd_cookies) {
+      qDebug("Unregistering event with cookie %ld", cookie);
+      alarmd_event_del(cookie);
     }
-    // Update existing event
-    qDebug("Updating profile event with cookie %ld", (long)cookie);
-    eve->alarm_time = toTime_t(event_time);
-    alarmd_event_update(eve);
+    pe->alarmd_cookies.clear();
+    // Then setting new events
+    long c1 = newProfileEvent(SILENT, pe->from_time, pe->days);
+    Q_ASSERT(c1 > 0);
+    if(c1 > 0)
+      pe->alarmd_cookies << c1;
+    long c2 = newProfileEvent(GENERAL, pe->to_time, pe->days);
+    Q_ASSERT(c2 > 0);
+    if(c2 > 0)
+      pe->alarmd_cookies << c2;
+    // Save in QSettings
+    ProfileEvent::setCookies(pe->getID(), pe->alarmd_cookies);
+    // Set Profile to SILENT if we are currently in the silent time slot
+    if(pe->affectsCurrentTime())
+      DBusBackend::setProfile(SILENT);
   }
 
 protected:
-  static void newProfileEvent(Profile p, const QTime &event_time) {
+  static long newProfileEvent(Profile p, const QTime &event_time, QList<int> days) {
+    Q_ASSERT(!days.empty());
+    if(days.empty()) days << NEVER;
     // Create the default alarm struct.
     alarm_event_t *newEvent = alarm_event_create();
     // Set the APP ID
@@ -91,9 +166,22 @@ protected:
     else
       alarm_event_set_title(newEvent, "general_profile");
     // Timing
-    newEvent->recur_secs = 86400; // 24 hours interval
-    newEvent->recur_count = -1; // Reoccur infinitely
-    newEvent->alarm_time = toTime_t(event_time);
+    if(days.first() == EVERY_DAY) {
+      newEvent->recur_secs = 86400; // 24 hours
+      newEvent->recur_count = -1; // Reoccur infinitely
+      newEvent->alarm_time = toTime_t(event_time); // Set event time
+    } else {
+      if(days.first() == NEVER) {
+        newEvent->alarm_time = toTime_t(event_time); // Set event time
+      } else {
+        newEvent->recur_secs = 0; // We re not using this way for recurrence
+        alarm_recur_t* recur = alarm_event_add_recurrences(newEvent, 1);
+        // Set event time
+        recur->mask_hour |= (1ul << event_time.hour());
+        recur->mask_min |= (1ull << event_time.minute());
+        recur->mask_wday |= daysToMask(days);
+      }
+    }
     //Add 1 action to our alarm event, and assign it to the "act" variable
     alarm_action_t *act = alarm_event_add_actions(newEvent, 1);
     // Actions are documented here:
@@ -116,20 +204,10 @@ protected:
     }
 
     // Finally with everything setup, try to add your event to the alarm queue
-    const cookie_t &cookie = alarmd_event_add(newEvent);
-    if(cookie != 0) {
-      // Save cookie
-      QSettings settings("TimedSilencer", "TimedSilencer");
-      if(p == SILENT) {
-        qDebug("Saving silent profile event cookie: %ld", (long)cookie);
-        settings.setValue("silencing_cookie", static_cast<const qlonglong>(cookie));
-      } else {
-        qDebug("Saving silent general event cookie: %ld", (long)cookie);
-        settings.setValue("unsilencing_cookie", static_cast<const qlonglong>(cookie));
-      }
-      return;
-    }
-    qDebug("ERROR: Failed to add profile event to the queue!");
+    long cookie = alarmd_event_add(newEvent);
+    // Free all dynamic memory associated with the alarm event
+    alarm_event_delete(newEvent);
+    return cookie;
   }
 };
 
diff --git a/checklistdelegate.cpp b/checklistdelegate.cpp
new file mode 100644 (file)
index 0000000..427d628
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * This file is part of TimedSilencer.
+ *
+ *  TimedSilencer is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  TimedSilencer is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with TimedSilencer.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <QPainter>
+#include <QItemDelegate>
+#include "checklistdelegate.h"
+
+CheckListDelegate::CheckListDelegate()
+{
+
+}
+
+void CheckListDelegate::paint(QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index) const {
+  // Save painter
+  painter->save();
+
+  QStyleOptionViewItem opt = option;
+  opt.displayAlignment = Qt::AlignCenter;
+  QStyledItemDelegate::paint(painter, opt, index);
+
+  if (option.state & QStyle::State_Selected) {
+    // Is selected
+    // Draw checkbox
+    QIcon cbIco = QIcon::fromTheme("widgets_tickmark_list");
+    QPixmap cbPix = cbIco.pixmap(cbIco.actualSize(option.decorationSize));
+    //qDebug("Pix size: (%d, %d)", cbPix.width(), cbPix.height());
+    QRect cbRect = option.rect;
+    cbRect.setLeft(cbRect.left()+(cbRect.width()-cbPix.width()));
+    int diff_height = cbRect.height() - cbPix.height();
+    cbRect.setHeight(cbPix.height());
+    cbRect.moveBottom(cbRect.bottom()+(diff_height/2.));
+    //qDebug("Rect size: (%d, %d)", cbRect.width(), cbRect.height());
+    painter->drawPixmap(cbRect, cbPix);
+  }
+
+  // Restore painter
+  painter->restore();
+}
diff --git a/checklistdelegate.h b/checklistdelegate.h
new file mode 100644 (file)
index 0000000..22bc5f0
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * This file is part of TimedSilencer.
+ *
+ *  TimedSilencer is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  TimedSilencer is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with TimedSilencer.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef CHECKLISTDELEGATE_H
+#define CHECKLISTDELEGATE_H
+
+#include <QStyledItemDelegate>
+
+class CheckListDelegate : public QStyledItemDelegate
+{
+public:
+    CheckListDelegate();
+    void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const;
+
+};
+
+#endif // CHECKLISTDELEGATE_H
diff --git a/eventlistdelegate.cpp b/eventlistdelegate.cpp
new file mode 100644 (file)
index 0000000..600d547
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * This file is part of TimedSilencer.
+ *
+ *  TimedSilencer is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  TimedSilencer is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with TimedSilencer.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <QIcon>
+#include <QPainter>
+#include "eventlistdelegate.h"
+#include "switchingeventlist.h"
+
+EventListDelegate::EventListDelegate()
+{
+}
+
+void EventListDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const {
+  if(index.column() == EV_STATUS) {
+    // Draw checkbox
+    QIcon::fromTheme("general_tickmark_checked");
+    // Is selected
+    // Draw checkbox
+    QIcon cbIco;
+    if(index.data().toBool()) {
+      cbIco = QIcon::fromTheme("clock_alarm_on");
+    } else {
+      cbIco = QIcon::fromTheme("clock_alarm_off");
+    }
+    QPixmap cbPix = cbIco.pixmap(cbIco.actualSize(option.decorationSize));
+    QRect cbRect = option.rect;
+    cbRect.setWidth(cbPix.width());
+    cbRect.setHeight(cbPix.height());
+    cbRect.moveCenter(option.rect.center());;
+    painter->drawPixmap(cbRect, cbPix);
+  } else {
+    QStyleOptionViewItem opt = option;
+    opt.displayAlignment = Qt::AlignCenter;
+    QStyledItemDelegate::paint(painter, opt, index);
+  }
+}
diff --git a/eventlistdelegate.h b/eventlistdelegate.h
new file mode 100644 (file)
index 0000000..f477490
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * This file is part of TimedSilencer.
+ *
+ *  TimedSilencer is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  TimedSilencer is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with TimedSilencer.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef EVENTLISTDELEGATE_H
+#define EVENTLISTDELEGATE_H
+
+#include <QStyledItemDelegate>
+
+class EventListDelegate : public QStyledItemDelegate
+{
+public:
+    EventListDelegate();
+    void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const;
+};
+
+#endif // EVENTLISTDELEGATE_H
index 796dfd4..431ab19 100644 (file)
--- a/main.cpp
+++ b/main.cpp
@@ -37,7 +37,7 @@ int main(int argc, char *argv[])
     QString param = QString::fromLocal8Bit(argv[1]);
     if(param == "--disable") {
       std::cout << "Disabling the timed silencer events..." << std::endl;
-      AlarmdBackend::deleteEvents();
+      AlarmdBackend::deleteAllEvents();
       return 0;
     }
   }
index e4ed214..89392a3 100644 (file)
 #include <QPushButton>
 #include <QHBoxLayout>
 #include <QCloseEvent>
-
+#include <QIcon>
 #include "mainwindow.h"
-#include "alarmd_backend.h"
-#include "dbus_backend.h"
+#include "switchingeventlist.h"
+#include "newalarmdlg.h"
 
 MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) {
   setCentralWidget(new QWidget());
-  QHBoxLayout *hori_layout = new QHBoxLayout(centralWidget());
-  QVBoxLayout *verticalLayoutL = new QVBoxLayout();
-  verticalLayoutL->addItem(new QSpacerItem(20, 40, QSizePolicy::Minimum, QSizePolicy::Expanding));
-  QLabel *from_lbl = new QLabel(tr("Use the silent profile between"));
-  from_lbl->setAlignment(Qt::AlignHCenter);
-  verticalLayoutL->addWidget(from_lbl);
-  from_button = new QMaemo5ValueButton();
-  from_button->setPickSelector(new QMaemo5TimePickSelector());
-  verticalLayoutL->addWidget(from_button);
-  QLabel *to_lbl = new QLabel(tr("and"));
-  to_lbl->setAlignment(Qt::AlignHCenter);
-  verticalLayoutL->addWidget(to_lbl);
-  to_button = new QMaemo5ValueButton();
-  to_button->setPickSelector(new QMaemo5TimePickSelector());
-  verticalLayoutL->addWidget(to_button);
-  // Status
-  verticalLayoutL->addItem(new QSpacerItem(20, 40, QSizePolicy::Minimum, QSizePolicy::Expanding));
-  cb_enable = new QCheckBox(tr("Activated"));
-  verticalLayoutL->addWidget(cb_enable);
-  hori_layout->addLayout(verticalLayoutL);
-  QVBoxLayout *verticalLayoutR = new QVBoxLayout;
-  verticalLayoutR->addItem(new QSpacerItem(20, 40, QSizePolicy::Minimum, QSizePolicy::Expanding));
-  done_btn = new QPushButton(tr("Save"));
-  done_btn->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
-  connect(done_btn, SIGNAL(clicked()), this, SLOT(saveAndClose()));
-  verticalLayoutR->addWidget(done_btn);
-  hori_layout->addLayout(verticalLayoutR);
-  // Load settings
-  loadSettings();
+  QVBoxLayout *vLayout = new QVBoxLayout(centralWidget());
+  addEventBtn = new QPushButton(QIcon::fromTheme("general_add"), tr("New profile switching event"));
+  connect(addEventBtn, SIGNAL(clicked()), this, SLOT(addEvent()));
+  vLayout->addWidget(addEventBtn);
+  eventList = new SwitchingEventList;
+  vLayout->addWidget(eventList);
   // Auto rotation
   setAttribute(Qt::WA_Maemo5AutoOrientation, true);
 }
 
 MainWindow::~MainWindow() {
-  delete from_button;
-  delete to_button;
-  delete cb_enable;
-  delete done_btn;
+  delete addEventBtn;
+  delete eventList;
 }
 
-void MainWindow::saveAndClose() {
-  // Save the settings and set the events
-  if(cb_enable->isChecked()) {
-    setProfileEvents();
-    QMaemo5InformationBox::information(this, tr("The daily profile switching is activated"), 0);
-  } else {
-    AlarmdBackend::deleteEvents();
-    QMaemo5InformationBox::information(this, tr("The daily profile switching is deactivated"), 0);
-  }
-  saveSettings();
-  // Close the window
-  close();
+void MainWindow::loadSettings() {
+
 }
 
 void MainWindow::saveSettings() {
-  QSettings settings("TimedSilencer", "TimedSilencer");
-  settings.setValue("from_time", static_cast<QMaemo5TimePickSelector*>(from_button->pickSelector())->currentTime());
-  settings.setValue("to_time", static_cast<QMaemo5TimePickSelector*>(to_button->pickSelector())->currentTime());
-  settings.setValue("enabled", cb_enable->isChecked());
-}
 
-void MainWindow::loadSettings() {
-  QSettings settings("TimedSilencer", "TimedSilencer");
-  QTime from_time = settings.value("from_time", QTime(22, 0)).toTime();
-  static_cast<QMaemo5TimePickSelector*>(from_button->pickSelector())->setCurrentTime(from_time);
-  QTime to_time = settings.value("to_time", QTime(8, 0)).toTime();
-  static_cast<QMaemo5TimePickSelector*>(to_button->pickSelector())->setCurrentTime(to_time);
-  cb_enable->setChecked(settings.value("enabled", false).toBool());
 }
 
-void MainWindow::setProfileEvents() {
-  // Set profile events in Alarmd
-  QTime from_time = static_cast<QMaemo5TimePickSelector*>(from_button->pickSelector())->currentTime();
-  qDebug("From time: %s", qPrintable(from_time.toString()));
-  AlarmdBackend::setProfileEvent(SILENT, from_time);
-  QTime to_time = static_cast<QMaemo5TimePickSelector*>(to_button->pickSelector())->currentTime();
-  AlarmdBackend::setProfileEvent(GENERAL, to_time);
-  qDebug("To time: %s", qPrintable(to_time.toString()));
-  // Update current profile
-  bool in_silent_mode = false;
-  QTime ctime = QTime::currentTime();
-  if(from_time < to_time) {
-    in_silent_mode = (ctime > from_time && ctime < to_time);
-  } else {
-    // to_time is the next day
-    in_silent_mode = (ctime > from_time || (ctime < from_time && ctime < to_time));
-  }
-  if(in_silent_mode)
-    DBusBackend::setProfile(SILENT);
-  /*else
-    DBusBackend::setProfile(GENERAL);*/
+void MainWindow::addEvent() {
+  NewAlarmDlg dlg(this);
+  connect(&dlg, SIGNAL(newEvent(QVariant)), eventList, SLOT(addNewEvent(QVariant)));
+  dlg.exec();
 }
+
index 1242af8..8d66bc3 100644 (file)
 
 #include <QMainWindow>
 
-struct QMaemo5ValueButton;
-struct QAction;
-struct QCheckBox;
 struct QPushButton;
+struct SwitchingEventList;
 
 class MainWindow : public QMainWindow {
   Q_OBJECT
@@ -33,16 +31,13 @@ public:
   ~MainWindow();
 
 protected slots:
-  void saveSettings();
   void loadSettings();
-  void setProfileEvents();
-  void saveAndClose();
+  void saveSettings();
+  void addEvent();
 
 private:
-  QMaemo5ValueButton *from_button, *to_button;
-  QAction *active_action;
-  QCheckBox *cb_enable;
-  QPushButton *done_btn;
+  QPushButton *addEventBtn;
+  SwitchingEventList *eventList;
 };
 
 #endif // MAINWINDOW_H
diff --git a/newalarmdlg.cpp b/newalarmdlg.cpp
new file mode 100644 (file)
index 0000000..8f7f21a
--- /dev/null
@@ -0,0 +1,185 @@
+/*
+ * This file is part of TimedSilencer.
+ *
+ *  TimedSilencer is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  TimedSilencer is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with TimedSilencer.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <QHBoxLayout>
+#include <QVBoxLayout>
+#include <QDialogButtonBox>
+#include <QLabel>
+#include <QPushButton>
+#include <QAbstractButton>
+#include <QSettings>
+#include <QCheckBox>
+#include <QMaemo5ValueButton>
+#include <QMaemo5TimePickSelector>
+#include <QMaemo5InformationBox>
+#include "newalarmdlg.h"
+#include "alarmd_backend.h"
+#include "qmaemo5weekdayspickselector.h"
+#include "profileevent.h"
+
+NewAlarmDlg::NewAlarmDlg(QWidget *parent, QByteArray edited_id) :
+    QDialog(parent)
+{
+  if(!edited_id.isNull()) {
+    pe = ProfileEvent::findByID(edited_id);
+  } else {
+    pe = 0;
+  }
+  if(pe) {
+    setWindowTitle(tr("Edit profile switching event"));
+  } else {
+    setWindowTitle(tr("New profile switching event"));
+  }
+  QHBoxLayout *hori_layout = new QHBoxLayout(this);
+  QVBoxLayout *verticalLayoutL = new QVBoxLayout();
+  verticalLayoutL->addWidget(new QLabel(tr("Use the silent profile")));
+  from_button = new QMaemo5ValueButton(tr("From"));
+  QMaemo5TimePickSelector *from_selector = new QMaemo5TimePickSelector();
+  if(pe) {
+    from_selector->setCurrentTime(pe->from_time);
+  } else {
+    from_selector->setCurrentTime(QTime(22, 30));
+  }
+  from_button->setPickSelector(from_selector);
+  from_button->setValueLayout(QMaemo5ValueButton::ValueBesideText);
+  verticalLayoutL->addWidget(from_button);
+  to_button = new QMaemo5ValueButton(tr("To"));
+  QMaemo5TimePickSelector *to_selector = new QMaemo5TimePickSelector();
+  if(pe) {
+    to_selector->setCurrentTime(pe->to_time);
+  } else {
+    to_selector->setCurrentTime(QTime(8, 0));
+  }
+  to_button->setPickSelector(to_selector);
+  to_button->setValueLayout(QMaemo5ValueButton::ValueBesideText);
+  verticalLayoutL->addWidget(to_button);
+  // Status
+  verticalLayoutL->addItem(new QSpacerItem(20, 40, QSizePolicy::Minimum, QSizePolicy::Expanding));
+  repeat_button = new QMaemo5ValueButton(tr("Repeat"));
+  repeat_button->setValueLayout(QMaemo5ValueButton::ValueBesideText);
+  QMaemo5WeekDaysPickSelector *weekDaysSelector = new QMaemo5WeekDaysPickSelector;
+  if(pe) {
+    weekDaysSelector->updateSelection(pe->days);
+  }
+  repeat_button->setPickSelector(weekDaysSelector);
+  verticalLayoutL->addWidget(repeat_button);
+  if(pe) {
+    cb_enable = new QCheckBox(tr("Activated"));
+    cb_enable->setChecked(pe->activated);
+    verticalLayoutL->addWidget(cb_enable);
+  } else {
+    cb_enable = 0;
+  }
+  hori_layout->addLayout(verticalLayoutL);
+  QVBoxLayout *verticalLayoutR = new QVBoxLayout;
+  verticalLayoutR->addItem(new QSpacerItem(20, 20, QSizePolicy::Minimum, QSizePolicy::Expanding));
+  button_box = new QDialogButtonBox(Qt::Vertical);
+  // Delete button
+  if(pe) {
+    delete_btn = new QPushButton(tr("Delete"));
+    connect(delete_btn, SIGNAL(clicked()), this, SLOT(deleteAndClose()));
+    button_box->addButton(delete_btn, QDialogButtonBox::ActionRole);
+  } else {
+    delete_btn = 0;
+  }
+  // Save button
+  done_btn = new QPushButton(tr("Save"));
+  connect(done_btn, SIGNAL(clicked()), this, SLOT(saveAndClose()));
+  button_box->addButton(done_btn, QDialogButtonBox::ActionRole);
+  verticalLayoutR->addWidget(button_box);
+  hori_layout->addLayout(verticalLayoutR);
+}
+
+NewAlarmDlg::~NewAlarmDlg() {
+  if(pe) delete pe;
+  delete button_box;
+}
+
+void NewAlarmDlg::saveAndClose() {
+  // Save QSettings
+  ProfileEvent *new_pe = saveEvent();
+  if(new_pe) {
+    // Update Alarmd events
+    if(pe && pe->activated) {
+      // Delete old alarmd events
+      AlarmdBackend::deleteEvents(pe);
+    }
+    if(new_pe->activated) {
+      // Add new alarmd events
+      AlarmdBackend::setProfileEvents(new_pe);
+    }
+    delete new_pe;
+  }
+  // Close the window
+  close();
+}
+
+void NewAlarmDlg::deleteAndClose() {
+  Q_ASSERT(pe);
+  // Remove Alarmd events
+  AlarmdBackend::deleteEvents(pe);
+  // Update QSettings
+  QSettings settings("TimedSilencer", "TimedSilencer");
+  QHash<QString, QVariant> events = settings.value("events").toHash();
+  Q_ASSERT(events.contains(pe->getID()));
+  events.remove(pe->getID());
+  settings.setValue("events", events);
+  // Notify MainWindow
+  emit deletedEvent(pe->getID());
+  close();
+}
+
+ProfileEvent* NewAlarmDlg::saveEvent() {
+  QSettings settings("TimedSilencer", "TimedSilencer");
+  ProfileEvent *new_pe = new ProfileEvent;
+  new_pe->from_time = static_cast<QMaemo5TimePickSelector*>(from_button->pickSelector())->currentTime();
+  new_pe->to_time = static_cast<QMaemo5TimePickSelector*>(to_button->pickSelector())->currentTime();
+  new_pe->days = static_cast<QMaemo5WeekDaysPickSelector*>(repeat_button->pickSelector())->selectedDays();
+  if(cb_enable)
+    new_pe->activated = cb_enable->isChecked();
+  QHash<QString, QVariant> events = settings.value("events").toHash();
+  if(pe && new_pe->getID() != pe->getID()) {
+    events.remove(pe->getID());
+  }
+  // Save
+  qDebug("Saving event...");
+  QVariant var_pe = new_pe->save();
+  if(pe) {
+    if(pe->getID() == new_pe->getID()) {
+      qDebug("ID did not change");
+      if(pe->activated != new_pe->activated) {
+        // Only the activated status may change without altering the ID
+        emit editedEvent(new_pe->getID(), new_pe->activated);
+      }
+    } else {
+      qDebug("ID changed");
+      emit deletedEvent(pe->getID());
+      emit newEvent(var_pe);
+    }
+  } else {
+    qDebug("New event");
+    if(events.contains(new_pe->getID())) {
+      QMaemo5InformationBox::information(parentWidget(), tr("This profile switching event already exists"));
+      return 0;
+    } else {
+      emit newEvent(var_pe);
+    }
+  }
+  events.insert(new_pe->getID(), var_pe);
+  settings.setValue("events", events);
+  return new_pe;
+}
diff --git a/newalarmdlg.h b/newalarmdlg.h
new file mode 100644 (file)
index 0000000..17a5e0c
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * This file is part of TimedSilencer.
+ *
+ *  TimedSilencer is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  TimedSilencer is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with TimedSilencer.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef NEWALARMDLG_H
+#define NEWALARMDLG_H
+
+#include <QDialog>
+#include <QVariant>
+
+struct QMaemo5ValueButton;
+struct QAction;
+struct QCheckBox;
+struct QPushButton;
+struct ProfileEvent;
+struct QDialogButtonBox;
+
+class NewAlarmDlg : public QDialog
+{
+  Q_OBJECT
+public:
+  explicit NewAlarmDlg(QWidget *parent = 0, QByteArray edited_id = QByteArray());
+  ~NewAlarmDlg();
+
+signals:
+  void newEvent(QVariant event);
+  void editedEvent(QByteArray id, bool new_status);
+  void deletedEvent(QByteArray id);
+
+public slots:
+  ProfileEvent* saveEvent();
+  void saveAndClose();
+  void deleteAndClose();
+
+private:
+  QMaemo5ValueButton *from_button, *to_button, *repeat_button;
+  QCheckBox *cb_enable;
+  QPushButton *delete_btn;
+  QPushButton *done_btn;
+  QDialogButtonBox *button_box;
+  ProfileEvent *pe;
+};
+
+#endif // NEWALARMDLG_H
diff --git a/profileevent.h b/profileevent.h
new file mode 100644 (file)
index 0000000..643dbfb
--- /dev/null
@@ -0,0 +1,161 @@
+/*
+ * This file is part of TimedSilencer.
+ *
+ *  TimedSilencer is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  TimedSilencer is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with TimedSilencer.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef PROFILEEVENT_H
+#define PROFILEEVENT_H
+
+#include <QTime>
+#include <QVariant>
+#include <QHash>
+#include <QCryptographicHash>
+#include <QStringList>
+#include <QSettings>
+
+enum WeekDay {NEVER, MON, TUE, WED, THU, FRI, SAT, SUN, EVERY_DAY};
+
+class ProfileEvent : public QObject {
+  Q_OBJECT
+private:
+  QByteArray id;
+
+public:
+  QTime from_time;
+  QTime to_time;
+  bool activated;
+  QList<int> days;
+  QList<long> alarmd_cookies;
+
+  ProfileEvent() {
+    // Activate as a default
+    activated = true;
+  }
+
+  QByteArray getID() {
+    if(id.isEmpty()) {
+      QCryptographicHash hasher(QCryptographicHash::Md5);
+      hasher.addData(from_time.toString().toLocal8Bit());
+      hasher.addData(to_time.toString().toLocal8Bit());
+      foreach(int i, days) hasher.addData(QByteArray::number(i));
+      id = hasher.result();
+    }
+    qDebug("getID(): %s", id.constData());
+    return id;
+  }
+
+  QVariant save() const {
+    QHash<QString, QVariant> m;
+    m["from_time"] = from_time;
+    m["to_time"] = to_time;
+    m["activated"] = activated;
+    QVariantList var_days;
+    foreach(const int& day, days) var_days << day;
+    m["days"] = var_days;
+    QVariantList var_cookies;
+    foreach(const long& c, alarmd_cookies) var_cookies << (qlonglong)c;
+    m["alarmd_cookies"] = var_cookies;
+    return m;
+  }
+
+  bool affectsCurrentTime() {
+    if(!activated) return false;
+    Q_ASSERT(!days.empty());
+    if(days.empty()) days << NEVER;
+    if(days.first() != EVERY_DAY && days.first() != NEVER) {
+      // Check if the current week day is affected by this event
+      if(!days.contains(QDate::currentDate().dayOfWeek())) return false;
+    }
+    // Ok, it is the right day, are we in the interval?
+    bool in_silent_mode = false;
+    QTime ctime = QTime::currentTime();
+    if(from_time < to_time) {
+      in_silent_mode = (ctime > from_time && ctime < to_time);
+    } else {
+      // to_time is the next day
+      in_silent_mode = (ctime > from_time || (ctime < from_time && ctime < to_time));
+    }
+    return in_silent_mode;
+  }
+
+  static ProfileEvent* load(QVariant v) {
+    QHash<QString, QVariant> m = v.toHash();
+    ProfileEvent *pe = new ProfileEvent();
+    pe->from_time = m.value("from_time").toTime();
+    pe->to_time = m.value("to_time").toTime();
+    pe->activated = m.value("activated").toBool();
+    QVariantList var_days = m.value("days").toList();
+    foreach(const QVariant& var_day, var_days) pe->days << var_day.toInt();
+    QVariantList var_cookies = m.value("alarmd_cookies").toList();
+    foreach(const QVariant& var_c, var_cookies) pe->alarmd_cookies << var_c.toLongLong();
+    return pe;
+  }
+
+  static QString formatDays(QList<int> selection) {
+    qDebug("CurrentValueText() called");
+    if(selection.isEmpty() || selection.contains(NEVER)) {
+      return tr("Never");
+    }
+    if(selection.contains(EVERY_DAY)) {
+      return tr("Every day");
+    }
+    QStringList selectedDays;
+    foreach(const int &i, selection) {
+      selectedDays << QDate::shortDayName(i);
+    }
+    return selectedDays.join(", ");
+  }
+
+  static ProfileEvent* findByID(QByteArray myid) {
+    QSettings settings("TimedSilencer", "TimedSilencer");
+    QHash<QString, QVariant> events = settings.value("events").toHash();
+    if(events.contains(myid)) {
+      return load(events.value(myid));
+    }
+    return 0;
+  }
+
+  static void clearCookies(QByteArray myid) {
+    QSettings settings("TimedSilencer", "TimedSilencer");
+    QHash<QString, QVariant> events = settings.value("events").toHash();
+    Q_ASSERT(events.contains(myid));
+    if(events.contains(myid)) {
+      qDebug("Clearing event cookies in QSettings");
+      ProfileEvent *pe = load(events.value(myid));
+      pe->alarmd_cookies.clear();
+      events[myid] = pe->save();
+      settings.setValue("events", events);
+      delete pe;
+    }
+  }
+
+  static void setCookies(QByteArray myid, QList<long> cookies) {
+    QSettings settings("TimedSilencer", "TimedSilencer");
+    QHash<QString, QVariant> events = settings.value("events").toHash();
+    Q_ASSERT(events.contains(myid));
+    if(events.contains(myid)) {
+      qDebug("Setting event cookies in QSettings");
+      ProfileEvent *pe = load(events.value(myid));
+      Q_ASSERT(pe->alarmd_cookies.empty());
+      pe->alarmd_cookies = cookies;
+      events[myid] = pe->save();
+      settings.setValue("events", events);
+      delete pe;
+    }
+  }
+
+};
+
+#endif // PROFILEEVENT_H
diff --git a/qmaemo5weekdayspickselector.cpp b/qmaemo5weekdayspickselector.cpp
new file mode 100644 (file)
index 0000000..2c87548
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * This file is part of TimedSilencer.
+ *
+ *  TimedSilencer is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  TimedSilencer is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with TimedSilencer.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <QDate>
+
+#include "qmaemo5weekdayspickselector.h"
+#include "qmaemo5weekdayspickwidget.h"
+#include "profileevent.h"
+
+QMaemo5WeekDaysPickSelector::QMaemo5WeekDaysPickSelector(QObject *parent): QMaemo5AbstractPickSelector(parent)
+{
+  pick_widget = new QMaemo5WeekDaysPickWidget;
+  connect(pick_widget, SIGNAL(selectedDays(QList<int>)), this, SLOT(updateSelection(QList<int>)));
+}
+
+QWidget* QMaemo5WeekDaysPickSelector::widget(QWidget* parent) {
+  Q_UNUSED(parent);
+  return pick_widget;
+}
+
+QString QMaemo5WeekDaysPickSelector::currentValueText() const {
+  qDebug("CurrentValueText() called");
+  return ProfileEvent::formatDays(selection);
+}
+
+void QMaemo5WeekDaysPickSelector::updateSelection(QList<int> new_sel) {
+  qDebug("New selection size: %d", new_sel.size());
+  selection = new_sel;
+  pick_widget->setSelected(selection);
+  emit selected(currentValueText());
+}
+
+QList<int> QMaemo5WeekDaysPickSelector::selectedDays() {
+  if(selection.empty()) selection << NEVER;
+  return selection;
+}
diff --git a/qmaemo5weekdayspickselector.h b/qmaemo5weekdayspickselector.h
new file mode 100644 (file)
index 0000000..2962c21
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * This file is part of TimedSilencer.
+ *
+ *  TimedSilencer is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  TimedSilencer is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with TimedSilencer.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef QMAEMO5WEEKDAYSPICKSELECTOR_H
+#define QMAEMO5WEEKDAYSPICKSELECTOR_H
+
+#include <QMaemo5AbstractPickSelector>
+#include <QList>
+
+struct QMaemo5WeekDaysPickWidget;
+
+class QMaemo5WeekDaysPickSelector : public QMaemo5AbstractPickSelector
+{
+  Q_OBJECT
+
+public:
+    QMaemo5WeekDaysPickSelector(QObject *parent=0);
+    QWidget* widget(QWidget* parent);
+    QString currentValueText() const;
+    QList<int> selectedDays();
+
+public slots:
+    void updateSelection(QList<int> new_sel);
+
+private:
+    QMaemo5WeekDaysPickWidget *pick_widget;
+    QList<int> selection;
+};
+
+#endif // QMAEMO5WEEKDAYSPICKSELECTOR_H
diff --git a/qmaemo5weekdayspickwidget.cpp b/qmaemo5weekdayspickwidget.cpp
new file mode 100644 (file)
index 0000000..2a40e52
--- /dev/null
@@ -0,0 +1,139 @@
+/*
+ * This file is part of TimedSilencer.
+ *
+ *  TimedSilencer is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  TimedSilencer is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with TimedSilencer.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <QListView>
+#include <QStandardItemModel>
+#include <QHeaderView>
+#include <QSpacerItem>
+#include <QHBoxLayout>
+#include <QVBoxLayout>
+#include <QPushButton>
+#include <QDialogButtonBox>
+#include <QItemSelectionModel>
+#include "qmaemo5weekdayspickwidget.h"
+#include "checklistdelegate.h"
+
+QMaemo5WeekDaysPickWidget::QMaemo5WeekDaysPickWidget(QWidget *parent) :
+    QDialog(parent)
+{
+  setAttribute(Qt::WA_DeleteOnClose);
+  setWindowTitle(tr("Repeat"));
+  QHBoxLayout *hLayout = new QHBoxLayout(this);
+  QVBoxLayout *vLayoutL = new QVBoxLayout;
+  QStandardItemModel *model = new QStandardItemModel(9, 1);
+  model->setItem(NEVER, 0, new QStandardItem(tr("Never")));
+  model->setItem(MON, 0, new QStandardItem(tr("Monday")));
+  model->setItem(TUE, 0, new QStandardItem(tr("Tuesday")));
+  model->setItem(WED, 0, new QStandardItem(tr("Wednesday")));
+  model->setItem(THU, 0, new QStandardItem(tr("Thursday")));
+  model->setItem(FRI, 0, new QStandardItem(tr("Friday")));
+  model->setItem(SAT, 0, new QStandardItem(tr("Saturday")));
+  model->setItem(SUN, 0, new QStandardItem(tr("Sunday")));
+  model->setItem(EVERY_DAY, 0, new QStandardItem(tr("Every day")));
+  daysList = new QListView;
+  daysList->setModel(model);
+  daysList->setItemDelegate(new CheckListDelegate);
+  connect(daysList, SIGNAL(activated(QModelIndex)), this, SLOT(ensureConsistentSelection(QModelIndex)));
+  // Select NEVER item
+  daysList->selectionModel()->select(daysList->model()->index(NEVER, 0), QItemSelectionModel::Select | QItemSelectionModel::Rows);
+  // Height hint
+  if (daysList->sizeHintForRow(0)>0)
+    daysList->setMinimumHeight(daysList->sizeHintForRow(0) * 5);
+  daysList->setSelectionMode(QAbstractItemView::MultiSelection);
+  daysList->setSelectionBehavior(QAbstractItemView::SelectRows);
+  vLayoutL->addWidget(daysList);
+  hLayout->addLayout(vLayoutL);
+  QVBoxLayout *vLayoutR = new QVBoxLayout;
+  vLayoutR->addItem(new QSpacerItem(20, 40, QSizePolicy::Minimum, QSizePolicy::Expanding));
+  button_box = new QDialogButtonBox(Qt::Vertical);
+  QPushButton *done_btn = new QPushButton(tr("Done"));
+  connect(done_btn, SIGNAL(clicked()), this, SLOT(emitSelectionAndClose()));
+  done_btn->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
+  button_box->addButton(done_btn, QDialogButtonBox::ActionRole);
+  vLayoutR->addWidget(button_box);
+  hLayout->addLayout(vLayoutR);
+}
+
+void QMaemo5WeekDaysPickWidget::setSelected(QList<int> days) {
+  if(days.empty()) {
+    daysList->selectionModel()->select(daysList->model()->index(NEVER, 0), QItemSelectionModel::Select | QItemSelectionModel::Rows);
+    return;
+  }
+  daysList->selectionModel()->clearSelection();
+  qDebug("setSelected, %d items", days.size());
+  foreach(const int &d, days) {
+    daysList->selectionModel()->select(daysList->model()->index(d, 0), QItemSelectionModel::Select | QItemSelectionModel::Rows);
+    if(d == EVERY_DAY)
+      ensureConsistentSelection(daysList->model()->index(d, 0));
+  }
+}
+
+void QMaemo5WeekDaysPickWidget::emitSelectionAndClose() {
+  qDebug("in emitSelectionAndClose()");
+  QList<int> selected_rows;
+  QModelIndexList selected_indexes = daysList->selectionModel()->selectedRows();
+  foreach(QModelIndex index, selected_indexes) {
+    selected_rows << index.row();
+  }
+  emit selectedDays(selected_rows);
+  close();
+}
+
+void QMaemo5WeekDaysPickWidget::ensureConsistentSelection(QModelIndex index) {
+  qDebug("Received a click");
+  switch(index.row()) {
+  case NEVER:
+    if(!daysList->selectionModel()->isSelected(index)) {
+      // Prevent unselect
+      daysList->selectionModel()->select(index, QItemSelectionModel::Select | QItemSelectionModel::Rows);
+      return;
+    }
+    daysList->selectionModel()->clearSelection();
+    daysList->selectionModel()->select(index, QItemSelectionModel::Select | QItemSelectionModel::Rows);
+    break;
+  case EVERY_DAY:
+    if(!daysList->selectionModel()->isSelected(index)) {
+      // Prevent unselect
+      daysList->selectionModel()->select(index, QItemSelectionModel::Select | QItemSelectionModel::Rows);
+      return;
+    }
+    if(daysList->selectionModel()->isRowSelected(NEVER, daysList->rootIndex())) {
+      // Unselect NEVER item
+      daysList->selectionModel()->select(daysList->model()->index(NEVER, 0), QItemSelectionModel::Deselect | QItemSelectionModel::Rows);
+    }
+    // Select all days
+    for(int i=MON; i<EVERY_DAY; ++i) {
+      daysList->selectionModel()->select(daysList->model()->index(i, 0), QItemSelectionModel::Select | QItemSelectionModel::Rows);
+    }
+    break;
+  default:
+    if(daysList->selectionModel()->isRowSelected(NEVER, daysList->rootIndex())) {
+      // Unselect NEVER item
+      daysList->selectionModel()->select(daysList->model()->index(NEVER, 0), QItemSelectionModel::Deselect | QItemSelectionModel::Rows);
+    }
+    if(!daysList->selectionModel()->isSelected(index)) {
+      if(daysList->selectionModel()->isRowSelected(EVERY_DAY, daysList->rootIndex())) {
+        // A Work day was unselected, unselect EVERY_DAY item
+        daysList->selectionModel()->select(daysList->model()->index(EVERY_DAY, 0), QItemSelectionModel::Deselect | QItemSelectionModel::Rows);
+      }
+      if(!daysList->selectionModel()->hasSelection()) {
+        // Select NEVER item
+        daysList->selectionModel()->select(daysList->model()->index(NEVER, 0), QItemSelectionModel::Select | QItemSelectionModel::Rows);
+      }
+    }
+  }
+}
diff --git a/qmaemo5weekdayspickwidget.h b/qmaemo5weekdayspickwidget.h
new file mode 100644 (file)
index 0000000..03498e4
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * This file is part of TimedSilencer.
+ *
+ *  TimedSilencer is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  TimedSilencer is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with TimedSilencer.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef QMAEMO5WEEKDAYSPICKWIDGET_H
+#define QMAEMO5WEEKDAYSPICKWIDGET_H
+
+#include <QDialog>
+#include <QModelIndex>
+
+#include "profileevent.h"
+
+struct QListView;
+struct QDialogButtonBox;
+
+class QMaemo5WeekDaysPickWidget : public QDialog
+{
+    Q_OBJECT
+public:
+    explicit QMaemo5WeekDaysPickWidget(QWidget *parent = 0);
+
+signals:
+    void selectedDays(QList<int> days);
+
+public slots:
+    void ensureConsistentSelection(QModelIndex index);
+    void emitSelectionAndClose();
+    void setSelected(QList<int> days);
+
+private:
+  QListView *daysList;
+  QDialogButtonBox *button_box;
+};
+
+#endif // QMAEMO5WEEKDAYSPICKWIDGET_H
diff --git a/switchingeventlist.cpp b/switchingeventlist.cpp
new file mode 100644 (file)
index 0000000..abcc147
--- /dev/null
@@ -0,0 +1,164 @@
+/*
+ * This file is part of TimedSilencer.
+ *
+ *  TimedSilencer is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  TimedSilencer is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with TimedSilencer.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <QStandardItemModel>
+#include <QHeaderView>
+#include <QSettings>
+#include <QHash>
+#include "profileevent.h"
+#include "switchingeventlist.h"
+#include "newalarmdlg.h"
+#include "eventlistdelegate.h"
+#include "alarmd_backend.h"
+
+SwitchingEventList::SwitchingEventList(QWidget *parent) :
+    QTableView(parent)
+{
+  setSelectionBehavior(QAbstractItemView::SelectRows);
+  model = new QStandardItemModel(0, 5);
+  // Set Header
+  model->setHeaderData(EV_STATUS, Qt::Horizontal, tr("Status"));
+  model->setHeaderData(EV_FROM, Qt::Horizontal, tr("From"));
+  model->setHeaderData(EV_TO, Qt::Horizontal, tr("To"));
+  model->setHeaderData(EV_REPEAT, Qt::Horizontal, tr("Repeat"));
+  setModel(model);
+  setItemDelegate(new EventListDelegate);
+  connect(this, SIGNAL(activated(QModelIndex)), this, SLOT(editEvent(QModelIndex)));
+  // Hide vertical header
+  verticalHeader()->setVisible(false);
+  horizontalHeader()->setStretchLastSection(true);
+  hideColumn(EV_ID);
+  // Load saved events
+  loadSavedEvents();
+}
+
+SwitchingEventList::~SwitchingEventList() {
+  delete model;
+}
+
+void SwitchingEventList::updateRow(int row, ProfileEvent *pe) {
+  model->setData(model->index(row, EV_STATUS), pe->activated);
+  model->setData(model->index(row, EV_FROM), pe->from_time.toString());
+  model->setData(model->index(row, EV_TO), pe->to_time.toString());
+  model->setData(model->index(row, EV_REPEAT), ProfileEvent::formatDays(pe->days));
+  model->setData(model->index(row, EV_ID), pe->getID());
+}
+
+void SwitchingEventList::editEvent(QModelIndex index) {
+  if(!index.isValid()) return;
+  QByteArray edited_id = model->data(model->index(index.row(), EV_ID)).toByteArray();
+  if(index.column() == EV_STATUS) {
+    // Toggle activated state
+    const bool new_status = !index.data().toBool();
+    model->setData(index, new_status);
+    // Alter Alarmd events
+    if(new_status) {
+      // Was activated
+      AlarmdBackend::setProfileEvents(edited_id);
+    } else {
+      // Was deactivated
+      AlarmdBackend::deleteEvents(edited_id);
+    }
+  } else {
+    NewAlarmDlg dlg(this, edited_id);
+    connect(&dlg, SIGNAL(editedEvent(QByteArray,bool)), this, SLOT(editEvent(QByteArray,bool)));
+    connect(&dlg, SIGNAL(deletedEvent(QByteArray)), this, SLOT(deleteEvent(QByteArray)));
+    connect(&dlg, SIGNAL(newEvent(QVariant)), this, SLOT(addNewEvent(QVariant)));
+    dlg.exec();
+  }
+}
+
+void SwitchingEventList::loadSavedEvents() {
+  qDebug("Loading saved events");
+  QSettings settings("TimedSilencer", "TimedSilencer");
+  QHash<QString, QVariant> events = settings.value("events").toHash();
+  // Check for < v0.6 settings
+  if(!settings.value("from_time", QTime()).toTime().isNull()) {
+    qDebug("Old settings from < v0.6 were detected, importing...");
+    ProfileEvent pe;
+    pe.activated = settings.value("enabled", false).toBool();
+    pe.from_time = settings.value("from_time").toTime();
+    pe.to_time = settings.value("to_time").toTime();
+    pe.days << EVERY_DAY;
+    // Cookies
+    long from_cookie = settings.value("silencing_cookie", 0).toLongLong();
+    if(from_cookie > 0)
+      pe.alarmd_cookies << from_cookie;
+    long to_cookie = settings.value("unsilencing_cookie", 0).toLongLong();
+    if(to_cookie > 0)
+      pe.alarmd_cookies << to_cookie;
+    if(to_cookie == 0 || from_cookie == 0)
+      pe.activated = 0;
+    events.insert(pe.getID(), pe.save());
+    // Remove old format values
+    settings.clear();
+    // Save in new format
+    settings.setValue("events", events);
+  }
+  // Load >= v0.6 settings
+  bool settings_change = false;
+  foreach(QVariant e, events.values()) {
+    ProfileEvent *pe = ProfileEvent::load(e);
+    // Check if still active
+    if(pe->activated && !AlarmdBackend::checkIfStillActive(pe)) {
+      qDebug("An existing profile switching event is no longer active, updating its status");
+      pe->activated = false;
+      events[pe->getID()] = pe->save();
+      settings_change = true;
+    }
+    // Add new model row
+    const int nb_rows = model->rowCount();
+    model->setRowCount(nb_rows+1);
+    updateRow(nb_rows, pe);
+    // Clean up
+    delete pe;
+  }
+  if(settings_change)
+    settings.setValue("events", events);
+}
+
+void SwitchingEventList::addNewEvent(QVariant var_event) {
+  qDebug("Adding a new event to the list");
+  ProfileEvent *pe = ProfileEvent::load(var_event);
+  // Add new model row
+  const int nb_rows = model->rowCount();
+  model->setRowCount(nb_rows+1);
+  updateRow(nb_rows, pe);
+  delete pe;
+}
+
+void SwitchingEventList::editEvent(QByteArray id, bool new_status) {
+  const int row = getRowFromID(id);
+  qDebug("Editing event at row %d", row);
+  Q_ASSERT(row >= 0);
+  model->setData(model->index(row, EV_STATUS), new_status);
+}
+
+void SwitchingEventList::deleteEvent(QByteArray id) {
+  const int row = getRowFromID(id);
+  qDebug("Deleting an event (row: %d)", row);
+  Q_ASSERT(row >= 0);
+  model->removeRow(row);
+}
+
+int SwitchingEventList::getRowFromID(QByteArray id) {
+  for(int i=0; i<model->rowCount(); ++i) {
+    if(model->data(model->index(i, EV_ID)).toByteArray() == id)
+      return i;
+  }
+  return -1;
+}
diff --git a/switchingeventlist.h b/switchingeventlist.h
new file mode 100644 (file)
index 0000000..64cbe21
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * This file is part of TimedSilencer.
+ *
+ *  TimedSilencer is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  TimedSilencer is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with TimedSilencer.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef SWITCHINGEVENTLIST_H
+#define SWITCHINGEVENTLIST_H
+
+#include <QTableView>
+struct QStandardItemModel;
+struct ProfileEvent;
+
+enum EventCols {EV_STATUS, EV_FROM, EV_TO, EV_REPEAT, EV_ID};
+
+class SwitchingEventList : public QTableView
+{
+    Q_OBJECT
+public:
+    explicit SwitchingEventList(QWidget *parent = 0);
+    ~SwitchingEventList();
+    int getRowFromID(QByteArray id);
+
+signals:
+
+public slots:
+    void addNewEvent(QVariant event);
+    void editEvent(QByteArray id, bool new_status);
+    void deleteEvent(QByteArray id);
+
+protected slots:
+    void loadSavedEvents();
+    void updateRow(int row, ProfileEvent *pe);
+    void editEvent(QModelIndex index);
+
+private:
+    QStandardItemModel *model;
+};
+
+#endif // SWITCHINGEVENTLIST_H