67 void Explorer::loadSensors() |
70 void Explorer::loadSensors() |
68 { |
71 { |
69 qDebug() << "Explorer::loadSensors"; |
72 qDebug() << "Explorer::loadSensors"; |
70 |
73 |
71 // Clear out anything that's in there now |
74 // Clear out anything that's in there now |
72 m_sensors->clear(); |
75 ui.sensors->clear(); |
73 |
76 |
74 foreach (const QByteArray &type, QSensor::sensorTypes()) { |
77 foreach (const QByteArray &type, QSensor::sensorTypes()) { |
75 qDebug() << "Found type" << type; |
78 qDebug() << "Found type" << type; |
76 // The type item. We don't add it yet because there may not be any sensors of this type |
|
77 // and we only show types that have sensors available. |
|
78 QTreeWidgetItem *typeItem = new QTreeWidgetItem(QStringList() << QString::fromLatin1(type)); |
|
79 bool added = false; |
|
80 foreach (const QByteArray &identifier, QSensor::sensorsForType(type)) { |
79 foreach (const QByteArray &identifier, QSensor::sensorsForType(type)) { |
81 qDebug() << "Found identifier" << identifier; |
80 qDebug() << "Found identifier" << identifier; |
82 // Don't put in sensors we can't connect to |
81 // Don't put in sensors we can't connect to |
83 QSensor sensor; |
82 QSensor sensor(type); |
84 sensor.setType(type); |
|
85 sensor.setIdentifier(identifier); |
83 sensor.setIdentifier(identifier); |
86 if (!sensor.connect()) { |
84 if (!sensor.connectToBackend()) { |
87 qDebug() << "Couldn't connect to" << identifier; |
85 qDebug() << "Couldn't connect to" << identifier; |
88 continue; |
86 continue; |
89 } |
87 } |
90 |
88 |
91 // Since we're adding a sensor we can go ahead and add the type (unless it has |
|
92 // already been added). |
|
93 if (!added) { |
|
94 qDebug() << "Adding type" << type; |
|
95 m_sensors->addTopLevelItem(typeItem); |
|
96 added = true; |
|
97 } |
|
98 qDebug() << "Adding identifier" << identifier; |
89 qDebug() << "Adding identifier" << identifier; |
99 (void)new QTreeWidgetItem(typeItem, QStringList() << QString::fromLatin1(identifier)); |
90 QTreeWidgetItem *item = new QTreeWidgetItem(QStringList() << QString::fromLatin1(identifier)); |
|
91 item->setData(0, Qt::UserRole, QString::fromLatin1(type)); |
|
92 ui.sensors->addTopLevelItem(item); |
100 } |
93 } |
101 // Cleanup if we didn't add the type |
94 } |
102 if (!added) { |
95 |
103 qDebug() << "Didn't add type" << type; |
96 resizeSensors(); |
104 delete typeItem; |
97 } |
105 } |
98 |
106 } |
99 void Explorer::resizeSensors() |
107 |
100 { |
108 // Don't hide stuff |
101 ui.sensors->resizeColumnToContents(0); |
109 m_sensors->expandAll(); |
102 int length = ui.sensors->header()->length() + 4; |
110 } |
103 ui.sensors->setFixedWidth(length); |
111 |
104 } |
112 void Explorer::clearReading() |
105 |
113 { |
106 void Explorer::on_sensors_currentItemChanged() |
114 m_reading->setRowCount(0); |
107 { |
115 } |
108 qDebug() << "Explorer::sensorSelected"; |
116 |
|
117 void Explorer::loadReading() |
|
118 { |
|
119 qDebug() << "Explorer::loadReading"; |
|
120 |
109 |
121 // Clear out anything that's in there now |
110 // Clear out anything that's in there now |
|
111 if (m_sensor) { |
|
112 delete m_sensor; |
|
113 m_sensor = 0; |
|
114 } |
|
115 clearSensorProperties(); |
122 clearReading(); |
116 clearReading(); |
123 |
117 |
124 // Check that we've selected an item |
118 // Check that we've selected an item |
125 QTreeWidgetItem *item = m_sensors->currentItem(); |
119 QTreeWidgetItem *item = ui.sensors->currentItem(); |
126 if (!item) { |
120 if (!item) { |
127 qWarning() << "Didn't select an item!"; |
121 qWarning() << "Didn't select an item!"; |
128 return; |
122 return; |
129 } |
123 } |
130 |
124 |
131 // Check that we've selected a sensor (which has a parent) |
125 QByteArray type = item->data(0, Qt::UserRole).toString().toLatin1(); |
132 QTreeWidgetItem *parent = item->parent(); |
|
133 if (!parent) { |
|
134 qWarning() << "Didn't select a sensor!"; |
|
135 return; |
|
136 } |
|
137 |
|
138 QByteArray type = parent->data(0, Qt::DisplayRole).toString().toLatin1(); |
|
139 QByteArray identifier = item->data(0, Qt::DisplayRole).toString().toLatin1(); |
126 QByteArray identifier = item->data(0, Qt::DisplayRole).toString().toLatin1(); |
140 |
127 |
141 // Connect to the sensor so we can probe it |
128 // Connect to the sensor so we can probe it |
142 QSensor sensor; |
129 m_sensor = new QSensor(type, this); |
143 sensor.setType(type); |
130 connect(m_sensor, SIGNAL(readingChanged()), this, SLOT(sensor_changed())); |
144 sensor.setIdentifier(identifier); |
131 m_sensor->setIdentifier(identifier); |
145 if (!sensor.connect()) { |
132 if (!m_sensor->connectToBackend()) { |
|
133 delete m_sensor; |
|
134 m_sensor = 0; |
146 qWarning() << "Can't connect to the sensor!"; |
135 qWarning() << "Can't connect to the sensor!"; |
147 return; |
136 return; |
148 } |
137 } |
149 |
138 |
|
139 loadSensorProperties(); |
|
140 loadReading(); |
|
141 |
|
142 adjustTableColumns(ui.sensorprops); |
|
143 adjustTableColumns(ui.reading); |
|
144 QTimer::singleShot(100, this, SLOT(adjustSizes())); |
|
145 } |
|
146 |
|
147 void Explorer::clearReading() |
|
148 { |
|
149 ui.reading->setRowCount(0); |
|
150 } |
|
151 |
|
152 void Explorer::loadReading() |
|
153 { |
150 // Probe the reading using Qt's meta-object facilities |
154 // Probe the reading using Qt's meta-object facilities |
151 QSensorReading *reading = sensor.reading(); |
155 QSensorReading *reading = m_sensor->reading(); |
152 const QMetaObject *mo = reading->metaObject(); |
156 const QMetaObject *mo = reading->metaObject(); |
153 int firstProperty = QSensorReading::staticMetaObject.propertyOffset(); |
157 int firstProperty = QSensorReading::staticMetaObject.propertyOffset(); |
154 |
158 |
155 m_reading->setRowCount(mo->propertyCount() - firstProperty); |
159 ui.reading->setRowCount(mo->propertyCount() - firstProperty); |
156 |
160 |
157 for(int i = firstProperty; i < mo->propertyCount(); ++i) { |
161 for(int i = firstProperty; i < mo->propertyCount(); ++i) { |
158 int row = i - firstProperty; |
162 int row = i - firstProperty; |
159 QTableWidgetItem *index; |
163 QTableWidgetItem *index; |
160 if (row == 0) |
164 if (row == 0) |
161 // timestamp is not available via index |
165 // timestamp is not available via index |
162 index = new QTableWidgetItem(QLatin1String("N/A")); |
166 index = new QTableWidgetItem(QLatin1String("N/A")); |
163 else |
167 else |
164 index = new QTableWidgetItem(QVariant(row - 1).toString()); |
168 index = new QTableWidgetItem(QVariant(row - 1).toString()); |
165 QTableWidgetItem *prop = new QTableWidgetItem(mo->property(i).name()); |
169 QTableWidgetItem *prop = new QTableWidgetItem(mo->property(i).name()); |
166 QTableWidgetItem *type = new QTableWidgetItem(mo->property(i).typeName()); |
170 QString typeName = QLatin1String(mo->property(i).typeName()); |
167 m_reading->setItem(row, 0, index); |
171 int crap = typeName.lastIndexOf("::"); |
168 m_reading->setItem(row, 1, prop); |
172 if (crap != -1) |
169 m_reading->setItem(row, 2, type); |
173 typeName = typeName.mid(crap + 2); |
170 } |
174 QTableWidgetItem *type = new QTableWidgetItem(typeName); |
171 |
175 QTableWidgetItem *value = new QTableWidgetItem(); |
172 adjustReadingColumns(); |
176 |
|
177 index->setFlags(value->flags() ^ Qt::ItemIsEditable); |
|
178 prop->setFlags(value->flags() ^ Qt::ItemIsEditable); |
|
179 type->setFlags(value->flags() ^ Qt::ItemIsEditable); |
|
180 value->setFlags(value->flags() ^ Qt::ItemIsEditable); |
|
181 |
|
182 ui.reading->setItem(row, 0, index); |
|
183 ui.reading->setItem(row, 1, prop); |
|
184 ui.reading->setItem(row, 2, type); |
|
185 ui.reading->setItem(row, 3, value); |
|
186 } |
|
187 } |
|
188 |
|
189 void Explorer::clearSensorProperties() |
|
190 { |
|
191 ui.sensorprops->setRowCount(0); |
|
192 } |
|
193 |
|
194 void Explorer::loadSensorProperties() |
|
195 { |
|
196 ignoreItemChanged = true; |
|
197 |
|
198 // Probe the sensor using Qt's meta-object facilities |
|
199 const QMetaObject *mo = m_sensor->metaObject(); |
|
200 int firstProperty = QSensor::staticMetaObject.propertyOffset(); |
|
201 |
|
202 int rows = mo->propertyCount() - firstProperty; |
|
203 ui.sensorprops->setRowCount(rows); |
|
204 |
|
205 int offset = 0; |
|
206 for(int i = firstProperty; i < mo->propertyCount(); ++i) { |
|
207 int row = i - firstProperty - offset; |
|
208 QLatin1String name(mo->property(i).name()); |
|
209 if (name == "sensorid" || |
|
210 //name == "type" || |
|
211 name == "reading" || |
|
212 name == "connected" || |
|
213 name == "running" || |
|
214 name == "supportsPolling") { |
|
215 ++offset; |
|
216 continue; |
|
217 } |
|
218 QTableWidgetItem *prop = new QTableWidgetItem(name); |
|
219 QString typeName = QLatin1String(mo->property(i).typeName()); |
|
220 int crap = typeName.lastIndexOf("::"); |
|
221 if (crap != -1) |
|
222 typeName = typeName.mid(crap + 2); |
|
223 QTableWidgetItem *type = new QTableWidgetItem(typeName); |
|
224 QVariant v = mo->property(i).read(m_sensor); |
|
225 QString val; |
|
226 if (typeName == "qrangelist") { |
|
227 qrangelist rl = v.value<qrangelist>(); |
|
228 QStringList out; |
|
229 foreach (const qrange &r, rl) { |
|
230 if (r.first == r.second) |
|
231 out << QString("%1 Hz").arg(r.first); |
|
232 else |
|
233 out << QString("%1-%2 Hz").arg(r.first).arg(r.second); |
|
234 } |
|
235 val = out.join(", "); |
|
236 } else if (typeName == "qoutputrangelist") { |
|
237 qoutputrangelist rl = v.value<qoutputrangelist>(); |
|
238 QStringList out; |
|
239 foreach (const qoutputrange &r, rl) { |
|
240 out << QString("(%1, %2) += %3").arg(r.minimum).arg(r.maximum).arg(r.accuracy); |
|
241 } |
|
242 val = out.join(", "); |
|
243 } else { |
|
244 val = v.toString(); |
|
245 } |
|
246 QTableWidgetItem *value = new QTableWidgetItem(val); |
|
247 |
|
248 prop->setFlags(value->flags() ^ Qt::ItemIsEditable); |
|
249 type->setFlags(value->flags() ^ Qt::ItemIsEditable); |
|
250 if (!mo->property(i).isWritable()) { |
|
251 // clear the editable flag |
|
252 value->setFlags(value->flags() ^ Qt::ItemIsEditable); |
|
253 } |
|
254 |
|
255 ui.sensorprops->setItem(row, 0, prop); |
|
256 ui.sensorprops->setItem(row, 1, type); |
|
257 ui.sensorprops->setItem(row, 2, value); |
|
258 } |
|
259 |
|
260 // We don't add all properties |
|
261 ui.sensorprops->setRowCount(rows - offset); |
|
262 |
|
263 ignoreItemChanged = false; |
173 } |
264 } |
174 |
265 |
175 void Explorer::showEvent(QShowEvent *event) |
266 void Explorer::showEvent(QShowEvent *event) |
176 { |
267 { |
177 // Once we're visible, load the sensors |
268 // Once we're visible, load the sensors |
181 QMainWindow::showEvent(event); |
272 QMainWindow::showEvent(event); |
182 } |
273 } |
183 |
274 |
184 // Resize columns to fit the space. |
275 // Resize columns to fit the space. |
185 // This shouldn't be so hard! |
276 // This shouldn't be so hard! |
186 void Explorer::adjustReadingColumns() |
277 void Explorer::adjustTableColumns(QTableWidget *table) |
187 { |
278 { |
|
279 if (table->rowCount() == 0) { |
|
280 table->setFixedHeight(0); |
|
281 return; |
|
282 } |
|
283 |
188 // At least this is easy to do |
284 // At least this is easy to do |
189 m_reading->resizeColumnsToContents(); |
285 table->resizeColumnsToContents(); |
190 |
286 int length = table->verticalHeader()->length(); |
191 int indexWidth = m_reading->columnWidth(0); |
287 length += (length / static_cast<qreal>(table->verticalHeader()->count())); // Add 1 more (the header itself) |
192 int propWidth = m_reading->columnWidth(1); |
288 #ifdef MAEMO5 |
193 int typeWidth = m_reading->columnWidth(2); |
289 length += 10; // required for N900 UI |
194 |
290 #endif |
195 int suggestedWidth = indexWidth + propWidth + typeWidth; |
291 table->setFixedHeight(length); |
196 int actualWidth = m_reading->size().width(); |
292 |
|
293 int columns = table->columnCount(); |
|
294 QList<int> width; |
|
295 int suggestedWidth = 0; |
|
296 for (int i = 0; i < columns; ++i) { |
|
297 int cwidth = table->columnWidth(i); |
|
298 width << cwidth; |
|
299 suggestedWidth += cwidth; |
|
300 } |
|
301 |
|
302 int actualWidth = table->size().width(); |
197 //qDebug() << "suggestedWidth" << suggestedWidth << "actualWidth" << actualWidth; |
303 //qDebug() << "suggestedWidth" << suggestedWidth << "actualWidth" << actualWidth; |
198 |
304 |
199 // We only scale the columns up, we don't scale down |
305 // We only scale the columns up, we don't scale down |
200 if (actualWidth <= suggestedWidth) |
306 if (actualWidth <= suggestedWidth) |
201 return; |
307 return; |
202 |
308 |
203 qreal multiplier = actualWidth / static_cast<qreal>(suggestedWidth); |
309 qreal multiplier = actualWidth / static_cast<qreal>(suggestedWidth); |
204 indexWidth = multiplier * indexWidth; |
310 int currentSpace = 4; |
205 propWidth = multiplier * propWidth; |
311 for (int i = 0; i < columns; ++i) { |
206 typeWidth = multiplier * typeWidth; |
312 width[i] = multiplier * width[i]; |
|
313 currentSpace += width[i]; |
|
314 } |
207 |
315 |
208 // It ends up too big due to cell decorations or something. |
316 // It ends up too big due to cell decorations or something. |
209 // Make things smaller one pixel at a time in round robin fashion until we're good. |
317 // Make things smaller one pixel at a time in round robin fashion until we're good. |
210 int currentSpace = indexWidth + propWidth + typeWidth + 4; |
318 int i = 0; |
211 while (actualWidth < currentSpace) { |
319 while (currentSpace > actualWidth) { |
212 if (actualWidth < currentSpace) { |
320 --width[i]; |
213 --indexWidth; |
321 --currentSpace; |
214 --currentSpace; |
322 i = (i + 1) % columns; |
|
323 } |
|
324 |
|
325 for (int i = 0; i < columns; ++i) { |
|
326 table->setColumnWidth(i, width[i]); |
|
327 } |
|
328 |
|
329 table->setMinimumWidth(suggestedWidth); |
|
330 } |
|
331 |
|
332 void Explorer::adjustSizes() |
|
333 { |
|
334 adjustTableColumns(ui.reading); |
|
335 adjustTableColumns(ui.sensorprops); |
|
336 } |
|
337 |
|
338 void Explorer::resizeEvent(QResizeEvent *event) |
|
339 { |
|
340 resizeSensors(); |
|
341 adjustSizes(); |
|
342 |
|
343 QMainWindow::resizeEvent(event); |
|
344 } |
|
345 |
|
346 void Explorer::on_start_clicked() |
|
347 { |
|
348 m_sensor->start(); |
|
349 QTimer::singleShot(0, this, SLOT(loadSensorProperties())); |
|
350 } |
|
351 |
|
352 void Explorer::on_stop_clicked() |
|
353 { |
|
354 m_sensor->stop(); |
|
355 QTimer::singleShot(0, this, SLOT(loadSensorProperties())); |
|
356 } |
|
357 |
|
358 void Explorer::sensor_changed() |
|
359 { |
|
360 QSensorReading *reading = m_sensor->reading(); |
|
361 filter(reading); |
|
362 } |
|
363 |
|
364 bool Explorer::filter(QSensorReading *reading) |
|
365 { |
|
366 const QMetaObject *mo = reading->metaObject(); |
|
367 int firstProperty = QSensorReading::staticMetaObject.propertyOffset(); |
|
368 |
|
369 for(int i = firstProperty; i < mo->propertyCount(); ++i) { |
|
370 int row = i - firstProperty; |
|
371 QString typeName = QLatin1String(mo->property(i).typeName()); |
|
372 int crap = typeName.lastIndexOf("::"); |
|
373 if (crap != -1) |
|
374 typeName = typeName.mid(crap + 2); |
|
375 QLatin1String name(mo->property(i).name()); |
|
376 QTableWidgetItem *value = ui.reading->item(row, 3); |
|
377 QVariant val = mo->property(i).read(reading); |
|
378 if (typeName == "qtimestamp") { |
|
379 value->setText(QString("%1").arg(val.value<qtimestamp>())); |
|
380 } else if (typeName == "LightLevel") { |
|
381 QString text; |
|
382 switch (val.toInt()) { |
|
383 case 1: |
|
384 text = "Dark"; |
|
385 break; |
|
386 case 2: |
|
387 text = "Twilight"; |
|
388 break; |
|
389 case 3: |
|
390 text = "Light"; |
|
391 break; |
|
392 case 4: |
|
393 text = "Bright"; |
|
394 break; |
|
395 case 5: |
|
396 text = "Sunny"; |
|
397 break; |
|
398 default: |
|
399 text = "Undefined"; |
|
400 break; |
|
401 } |
|
402 value->setText(text); |
|
403 } else { |
|
404 value->setText(val.toString()); |
215 } |
405 } |
216 if (actualWidth < currentSpace) { |
406 } |
217 --propWidth; |
407 |
218 --currentSpace; |
408 adjustTableColumns(ui.reading); |
219 } |
409 //QTimer::singleShot(0, this, SLOT(adjustSizes())); |
220 if (actualWidth < currentSpace) { |
410 |
221 --typeWidth; |
411 return false; |
222 --currentSpace; |
412 } |
223 } |
413 |
224 } |
414 void Explorer::on_sensorprops_itemChanged(QTableWidgetItem *item) |
225 |
415 { |
226 m_reading->setColumnWidth(0, indexWidth); |
416 if (ignoreItemChanged) |
227 m_reading->setColumnWidth(1, propWidth); |
417 return; |
228 m_reading->setColumnWidth(2, typeWidth); |
418 if (!(item->flags() & Qt::ItemIsEditable)) |
229 } |
419 return; |
230 |
420 |
231 bool Explorer::eventFilter(QObject *obj, QEvent *event) |
421 int row = item->row(); |
232 { |
422 QString name = ui.sensorprops->item(row, 0)->text(); |
233 if (obj == m_reading && event->type() == QEvent::Resize) { |
423 QVariant value = item->text(); |
234 // If the table resizes, adjust the column sizes automatically |
424 |
235 adjustReadingColumns(); |
425 qDebug() << "setProperty" << name << value; |
236 } |
426 m_sensor->setProperty(name.toLatin1().constData(), QVariant(value)); |
237 |
427 |
238 return QMainWindow::eventFilter(obj, event); |
428 QTimer::singleShot(0, this, SLOT(loadSensorProperties())); |
239 } |
429 } |
240 |
430 |