Unity 8
windowstatestorage.cpp
1 /*
2  * Copyright 2015 Canonical Ltd.
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU Lesser General Public License as published by
6  * the Free Software Foundation; version 3.
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11  * GNU Lesser General Public License for more details.
12  *
13  * You should have received a copy of the GNU Lesser General Public License
14  * along with this program. If not, see <http://www.gnu.org/licenses/>.
15  */
16 
17 #include "windowstatestorage.h"
18 
19 #include <QtConcurrent>
20 #include <QDebug>
21 #include <QFutureSynchronizer>
22 #include <QSqlQuery>
23 #include <QSqlError>
24 #include <QSqlResult>
25 #include <QRect>
26 
27 QMutex WindowStateStorage::s_mutex;
28 
29 WindowStateStorage::WindowStateStorage(QObject *parent):
30  QObject(parent)
31 {
32  QString dbPath = QDir::homePath() + "/.cache/unity8/";
33  m_db = QSqlDatabase::addDatabase(QStringLiteral("QSQLITE"));
34  QDir dir;
35  dir.mkpath(dbPath);
36  m_db.setDatabaseName(dbPath + "windowstatestorage.sqlite");
37  initdb();
38 }
39 
40 WindowStateStorage::~WindowStateStorage()
41 {
42  QFutureSynchronizer<void> futureSync;
43  for (int i = 0; i < m_asyncQueries.count(); ++i) {
44  futureSync.addFuture(m_asyncQueries[i]);
45  }
46  futureSync.waitForFinished();
47  m_db.close();
48 }
49 
50 void WindowStateStorage::saveState(const QString &windowId, WindowStateStorage::WindowState state)
51 {
52  const QString queryString = QStringLiteral("INSERT OR REPLACE INTO state (windowId, state) values ('%1', '%2');")
53  .arg(windowId)
54  .arg((int)state);
55 
56  saveValue(queryString);
57 }
58 
59 WindowStateStorage::WindowState WindowStateStorage::getState(const QString &windowId, WindowStateStorage::WindowState defaultValue) const
60 {
61  const QString queryString = QStringLiteral("SELECT * FROM state WHERE windowId = '%1';")
62  .arg(windowId);
63 
64  QSqlQuery query = getValue(queryString);
65 
66  if (!query.first()) {
67  return defaultValue;
68  }
69  return (WindowState)query.value("state").toInt();
70 }
71 
72 void WindowStateStorage::saveGeometry(const QString &windowId, const QRect &rect)
73 {
74  const QString queryString = QStringLiteral("INSERT OR REPLACE INTO geometry (windowId, x, y, width, height) values ('%1', '%2', '%3', '%4', '%5');")
75  .arg(windowId)
76  .arg(rect.x())
77  .arg(rect.y())
78  .arg(rect.width())
79  .arg(rect.height());
80 
81  saveValue(queryString);
82 }
83 
84 void WindowStateStorage::executeAsyncQuery(const QString &queryString)
85 {
86  QMutexLocker l(&s_mutex);
87  QSqlQuery query;
88 
89  bool ok = query.exec(queryString);
90  if (!ok) {
91  qWarning() << "Error executing query" << queryString
92  << "Driver error:" << query.lastError().driverText()
93  << "Database error:" << query.lastError().databaseText();
94  }
95 }
96 
97 QRect WindowStateStorage::getGeometry(const QString &windowId, const QRect &defaultValue) const
98 {
99  QString queryString = QStringLiteral("SELECT * FROM geometry WHERE windowId = '%1';")
100  .arg(windowId);
101 
102  QSqlQuery query = getValue(queryString);
103 
104  if (!query.first()) {
105  return defaultValue;
106  }
107  return QRect(query.value(QStringLiteral("x")).toInt(), query.value(QStringLiteral("y")).toInt(), query.value(QStringLiteral("width")).toInt(), query.value(QStringLiteral("height")).toInt());
108 }
109 
110 void WindowStateStorage::initdb()
111 {
112  m_db.open();
113  if (!m_db.open()) {
114  qWarning() << "Error opening state database:" << m_db.lastError().driverText() << m_db.lastError().databaseText();
115  return;
116  }
117 
118  if (!m_db.tables().contains(QStringLiteral("geometry"))) {
119  QSqlQuery query;
120  query.exec(QStringLiteral("CREATE TABLE geometry(windowId TEXT UNIQUE, x INTEGER, y INTEGER, width INTEGER, height INTEGER);"));
121  }
122 
123  if (!m_db.tables().contains("state")) {
124  QSqlQuery query;
125  query.exec("CREATE TABLE state(windowId TEXT UNIQUE, state INTEGER);");
126  }
127 }
128 
129 void WindowStateStorage::saveValue(const QString &queryString)
130 {
131  QMutexLocker mutexLocker(&s_mutex);
132 
133  QFuture<void> future = QtConcurrent::run(executeAsyncQuery, queryString);
134  m_asyncQueries.append(future);
135 
136  QFutureWatcher<void> *futureWatcher = new QFutureWatcher<void>();
137  futureWatcher->setFuture(future);
138  connect(futureWatcher, &QFutureWatcher<void>::finished,
139  this,
140  [=](){ m_asyncQueries.removeAll(futureWatcher->future());
141  futureWatcher->deleteLater(); });
142 }
143 
144 QSqlQuery WindowStateStorage::getValue(const QString &queryString) const
145 {
146  QMutexLocker l(&s_mutex);
147  QSqlQuery query;
148 
149  bool ok = query.exec(queryString);
150  if (!ok) {
151  qWarning() << "Error retrieving database query:" << queryString
152  << "Driver error:" << query.lastError().driverText()
153  << "Database error:" << query.lastError().databaseText();
154  }
155  return query;
156 }