qtmobility/examples/sensors/sensor_explorer/explorer.cpp
changeset 4 90517678cc4f
parent 1 2b40d63a9c3d
child 5 453da2cfceef
--- a/qtmobility/examples/sensors/sensor_explorer/explorer.cpp	Fri Apr 16 15:51:22 2010 +0300
+++ b/qtmobility/examples/sensors/sensor_explorer/explorer.cpp	Mon May 03 13:18:40 2010 +0300
@@ -50,14 +50,17 @@
 
 Explorer::Explorer(QWidget *parent)
     : QMainWindow(parent)
+    , m_sensor(0)
+    , ignoreItemChanged(false)
 {
-    setupUi(this);
+    ui.setupUi(this);
+#ifdef MAEMO5
+    ui.label->hide();
+#endif
     // Clear out example data from the .ui file
-    m_sensors->clear();
+    ui.sensors->clear();
+    clearSensorProperties();
     clearReading();
-    // We need to know when this widget resizes
-    // so we can resize the columns
-    m_reading->installEventFilter(this);
 }
 
 Explorer::~Explorer()
@@ -69,90 +72,91 @@
     qDebug() << "Explorer::loadSensors";
 
     // Clear out anything that's in there now
-    m_sensors->clear();
+    ui.sensors->clear();
 
     foreach (const QByteArray &type, QSensor::sensorTypes()) {
         qDebug() << "Found type" << type;
-        // The type item. We don't add it yet because there may not be any sensors of this type
-        // and we only show types that have sensors available.
-        QTreeWidgetItem *typeItem = new QTreeWidgetItem(QStringList() << QString::fromLatin1(type));
-        bool added = false;
         foreach (const QByteArray &identifier, QSensor::sensorsForType(type)) {
             qDebug() << "Found identifier" << identifier;
             // Don't put in sensors we can't connect to
-            QSensor sensor;
-            sensor.setType(type);
+            QSensor sensor(type);
             sensor.setIdentifier(identifier);
-            if (!sensor.connect()) {
+            if (!sensor.connectToBackend()) {
                 qDebug() << "Couldn't connect to" << identifier;
                 continue;
             }
 
-            // Since we're adding a sensor we can go ahead and add the type (unless it has
-            // already been added).
-            if (!added) {
-                qDebug() << "Adding type" << type;
-                m_sensors->addTopLevelItem(typeItem);
-                added = true;
-            }
             qDebug() << "Adding identifier" << identifier;
-            (void)new QTreeWidgetItem(typeItem, QStringList() << QString::fromLatin1(identifier));
-        }
-        // Cleanup if we didn't add the type
-        if (!added) {
-            qDebug() << "Didn't add type" << type;
-            delete typeItem;
+            QTreeWidgetItem *item = new QTreeWidgetItem(QStringList() << QString::fromLatin1(identifier));
+            item->setData(0, Qt::UserRole, QString::fromLatin1(type));
+            ui.sensors->addTopLevelItem(item);
         }
     }
 
-    // Don't hide stuff
-    m_sensors->expandAll();
+    resizeSensors();
+}
+
+void Explorer::resizeSensors()
+{
+    ui.sensors->resizeColumnToContents(0);
+    int length = ui.sensors->header()->length() + 4;
+    ui.sensors->setFixedWidth(length);
 }
 
-void Explorer::clearReading()
+void Explorer::on_sensors_currentItemChanged()
 {
-    m_reading->setRowCount(0);
-}
-
-void Explorer::loadReading()
-{
-    qDebug() << "Explorer::loadReading";
+    qDebug() << "Explorer::sensorSelected";
 
     // Clear out anything that's in there now
+    if (m_sensor) {
+        delete m_sensor;
+        m_sensor = 0;
+    }
+    clearSensorProperties();
     clearReading();
 
     // Check that we've selected an item
-    QTreeWidgetItem *item = m_sensors->currentItem();
+    QTreeWidgetItem *item = ui.sensors->currentItem();
     if (!item) {
         qWarning() << "Didn't select an item!";
         return;
     }
 
-    // Check that we've selected a sensor (which has a parent)
-    QTreeWidgetItem *parent = item->parent();
-    if (!parent) {
-        qWarning() << "Didn't select a sensor!";
-        return;
-    }
-
-    QByteArray type = parent->data(0, Qt::DisplayRole).toString().toLatin1();
+    QByteArray type = item->data(0, Qt::UserRole).toString().toLatin1();
     QByteArray identifier = item->data(0, Qt::DisplayRole).toString().toLatin1();
 
     // Connect to the sensor so we can probe it
-    QSensor sensor;
-    sensor.setType(type);
-    sensor.setIdentifier(identifier);
-    if (!sensor.connect()) {
+    m_sensor = new QSensor(type, this);
+    connect(m_sensor, SIGNAL(readingChanged()), this, SLOT(sensor_changed()));
+    m_sensor->setIdentifier(identifier);
+    if (!m_sensor->connectToBackend()) {
+        delete m_sensor;
+        m_sensor = 0;
         qWarning() << "Can't connect to the sensor!";
         return;
     }
 
+    loadSensorProperties();
+    loadReading();
+
+    adjustTableColumns(ui.sensorprops);
+    adjustTableColumns(ui.reading);
+    QTimer::singleShot(100, this, SLOT(adjustSizes()));
+}
+
+void Explorer::clearReading()
+{
+    ui.reading->setRowCount(0);
+}
+
+void Explorer::loadReading()
+{
     // Probe the reading using Qt's meta-object facilities
-    QSensorReading *reading = sensor.reading();
+    QSensorReading *reading = m_sensor->reading();
     const QMetaObject *mo = reading->metaObject();
     int firstProperty = QSensorReading::staticMetaObject.propertyOffset();
 
-    m_reading->setRowCount(mo->propertyCount() - firstProperty);
+    ui.reading->setRowCount(mo->propertyCount() - firstProperty);
 
     for(int i = firstProperty; i < mo->propertyCount(); ++i) {
         int row = i - firstProperty;
@@ -163,13 +167,100 @@
         else
             index = new QTableWidgetItem(QVariant(row - 1).toString());
         QTableWidgetItem *prop = new QTableWidgetItem(mo->property(i).name());
-        QTableWidgetItem *type = new QTableWidgetItem(mo->property(i).typeName());
-        m_reading->setItem(row, 0, index);
-        m_reading->setItem(row, 1, prop);
-        m_reading->setItem(row, 2, type);
+        QString typeName = QLatin1String(mo->property(i).typeName());
+        int crap = typeName.lastIndexOf("::");
+        if (crap != -1)
+            typeName = typeName.mid(crap + 2);
+        QTableWidgetItem *type = new QTableWidgetItem(typeName);
+        QTableWidgetItem *value = new QTableWidgetItem();
+
+        index->setFlags(value->flags() ^ Qt::ItemIsEditable);
+        prop->setFlags(value->flags() ^ Qt::ItemIsEditable);
+        type->setFlags(value->flags() ^ Qt::ItemIsEditable);
+        value->setFlags(value->flags() ^ Qt::ItemIsEditable);
+
+        ui.reading->setItem(row, 0, index);
+        ui.reading->setItem(row, 1, prop);
+        ui.reading->setItem(row, 2, type);
+        ui.reading->setItem(row, 3, value);
+    }
+}
+
+void Explorer::clearSensorProperties()
+{
+    ui.sensorprops->setRowCount(0);
+}
+
+void Explorer::loadSensorProperties()
+{
+    ignoreItemChanged = true;
+
+    // Probe the sensor using Qt's meta-object facilities
+    const QMetaObject *mo = m_sensor->metaObject();
+    int firstProperty = QSensor::staticMetaObject.propertyOffset();
+
+    int rows = mo->propertyCount() - firstProperty;
+    ui.sensorprops->setRowCount(rows);
+
+    int offset = 0;
+    for(int i = firstProperty; i < mo->propertyCount(); ++i) {
+        int row = i - firstProperty - offset;
+        QLatin1String name(mo->property(i).name());
+        if (name == "sensorid" ||
+            //name == "type" ||
+            name == "reading" ||
+            name == "connected" ||
+            name == "running" ||
+            name == "supportsPolling") {
+            ++offset;
+            continue;
+        }
+        QTableWidgetItem *prop = new QTableWidgetItem(name);
+        QString typeName = QLatin1String(mo->property(i).typeName());
+        int crap = typeName.lastIndexOf("::");
+        if (crap != -1)
+            typeName = typeName.mid(crap + 2);
+        QTableWidgetItem *type = new QTableWidgetItem(typeName);
+        QVariant v = mo->property(i).read(m_sensor);
+        QString val;
+        if (typeName == "qrangelist") {
+            qrangelist rl = v.value<qrangelist>();
+            QStringList out;
+            foreach (const qrange &r, rl) {
+                if (r.first == r.second)
+                    out << QString("%1 Hz").arg(r.first);
+                else
+                    out << QString("%1-%2 Hz").arg(r.first).arg(r.second);
+            }
+            val = out.join(", ");
+        } else if (typeName == "qoutputrangelist") {
+            qoutputrangelist rl = v.value<qoutputrangelist>();
+            QStringList out;
+            foreach (const qoutputrange &r, rl) {
+                out << QString("(%1, %2) += %3").arg(r.minimum).arg(r.maximum).arg(r.accuracy);
+            }
+            val = out.join(", ");
+        } else {
+            val = v.toString();
+        }
+        QTableWidgetItem *value = new QTableWidgetItem(val);
+
+        prop->setFlags(value->flags() ^ Qt::ItemIsEditable);
+        type->setFlags(value->flags() ^ Qt::ItemIsEditable);
+        if (!mo->property(i).isWritable()) {
+            // clear the editable flag
+            value->setFlags(value->flags() ^ Qt::ItemIsEditable);
+        }
+
+        ui.sensorprops->setItem(row, 0, prop);
+        ui.sensorprops->setItem(row, 1, type);
+        ui.sensorprops->setItem(row, 2, value);
     }
 
-    adjustReadingColumns();
+    // We don't add all properties
+    ui.sensorprops->setRowCount(rows - offset);
+
+    ignoreItemChanged = false;
 }
 
 void Explorer::showEvent(QShowEvent *event)
@@ -183,17 +274,32 @@
 
 // Resize columns to fit the space.
 // This shouldn't be so hard!
-void Explorer::adjustReadingColumns()
+void Explorer::adjustTableColumns(QTableWidget *table)
 {
-    // At least this is easy to do
-    m_reading->resizeColumnsToContents();
+    if (table->rowCount() == 0) {
+        table->setFixedHeight(0);
+        return;
+    }
 
-    int indexWidth = m_reading->columnWidth(0);
-    int propWidth = m_reading->columnWidth(1);
-    int typeWidth = m_reading->columnWidth(2);
+    // At least this is easy to do
+    table->resizeColumnsToContents();
+    int length = table->verticalHeader()->length();
+    length += (length / static_cast<qreal>(table->verticalHeader()->count())); // Add 1 more (the header itself)
+#ifdef MAEMO5
+    length += 10; // required for N900 UI
+#endif
+    table->setFixedHeight(length);
 
-    int suggestedWidth = indexWidth + propWidth + typeWidth;
-    int actualWidth = m_reading->size().width();
+    int columns = table->columnCount();
+    QList<int> width;
+    int suggestedWidth = 0;
+    for (int i = 0; i < columns; ++i) {
+        int cwidth = table->columnWidth(i);
+        width << cwidth;
+        suggestedWidth += cwidth;
+    }
+
+    int actualWidth = table->size().width();
     //qDebug() << "suggestedWidth" << suggestedWidth << "actualWidth" << actualWidth;
 
     // We only scale the columns up, we don't scale down
@@ -201,40 +307,124 @@
         return;
 
     qreal multiplier = actualWidth / static_cast<qreal>(suggestedWidth);
-    indexWidth = multiplier * indexWidth;
-    propWidth = multiplier * propWidth;
-    typeWidth = multiplier * typeWidth;
+    int currentSpace = 4;
+    for (int i = 0; i < columns; ++i) {
+        width[i] = multiplier * width[i];
+        currentSpace += width[i];
+    }
 
     // It ends up too big due to cell decorations or something.
     // Make things smaller one pixel at a time in round robin fashion until we're good.
-    int currentSpace = indexWidth + propWidth + typeWidth + 4;
-    while (actualWidth < currentSpace) {
-        if (actualWidth < currentSpace) {
-            --indexWidth;
-            --currentSpace;
-        }
-        if (actualWidth < currentSpace) {
-            --propWidth;
-            --currentSpace;
-        }
-        if (actualWidth < currentSpace) {
-            --typeWidth;
-            --currentSpace;
+    int i = 0;
+    while (currentSpace > actualWidth) {
+        --width[i];
+        --currentSpace;
+        i = (i + 1) % columns;
+    }
+
+    for (int i = 0; i < columns; ++i) {
+        table->setColumnWidth(i, width[i]);
+    }
+
+    table->setMinimumWidth(suggestedWidth);
+}
+
+void Explorer::adjustSizes()
+{
+    adjustTableColumns(ui.reading);
+    adjustTableColumns(ui.sensorprops);
+}
+
+void Explorer::resizeEvent(QResizeEvent *event)
+{
+    resizeSensors();
+    adjustSizes();
+
+    QMainWindow::resizeEvent(event);
+}
+
+void Explorer::on_start_clicked()
+{
+    m_sensor->start();
+    QTimer::singleShot(0, this, SLOT(loadSensorProperties()));
+}
+
+void Explorer::on_stop_clicked()
+{
+    m_sensor->stop();
+    QTimer::singleShot(0, this, SLOT(loadSensorProperties()));
+}
+
+void Explorer::sensor_changed()
+{
+    QSensorReading *reading = m_sensor->reading();
+    filter(reading);
+}
+
+bool Explorer::filter(QSensorReading *reading)
+{
+    const QMetaObject *mo = reading->metaObject();
+    int firstProperty = QSensorReading::staticMetaObject.propertyOffset();
+
+    for(int i = firstProperty; i < mo->propertyCount(); ++i) {
+        int row = i - firstProperty;
+        QString typeName = QLatin1String(mo->property(i).typeName());
+        int crap = typeName.lastIndexOf("::");
+        if (crap != -1)
+            typeName = typeName.mid(crap + 2);
+        QLatin1String name(mo->property(i).name());
+        QTableWidgetItem *value = ui.reading->item(row, 3);
+        QVariant val = mo->property(i).read(reading);
+        if (typeName == "qtimestamp") {
+            value->setText(QString("%1").arg(val.value<qtimestamp>()));
+        } else if (typeName == "LightLevel") {
+            QString text;
+            switch (val.toInt()) {
+            case 1:
+                text = "Dark";
+                break;
+            case 2:
+                text = "Twilight";
+                break;
+            case 3:
+                text = "Light";
+                break;
+            case 4:
+                text = "Bright";
+                break;
+            case 5:
+                text = "Sunny";
+                break;
+            default:
+                text = "Undefined";
+                break;
+            }
+            value->setText(text);
+        } else {
+            value->setText(val.toString());
         }
     }
 
-    m_reading->setColumnWidth(0, indexWidth);
-    m_reading->setColumnWidth(1, propWidth);
-    m_reading->setColumnWidth(2, typeWidth);
+    adjustTableColumns(ui.reading);
+    //QTimer::singleShot(0, this, SLOT(adjustSizes()));
+
+    return false;
 }
 
-bool Explorer::eventFilter(QObject *obj, QEvent *event)
+void Explorer::on_sensorprops_itemChanged(QTableWidgetItem *item)
 {
-    if (obj == m_reading && event->type() == QEvent::Resize) {
-        // If the table resizes, adjust the column sizes automatically
-        adjustReadingColumns();
-    }
+    if (ignoreItemChanged)
+        return;
+    if (!(item->flags() & Qt::ItemIsEditable))
+        return;
 
-    return QMainWindow::eventFilter(obj, event);
+    int row = item->row();
+    QString name = ui.sensorprops->item(row, 0)->text();
+    QVariant value = item->text();
+
+    qDebug() << "setProperty" << name << value;
+    m_sensor->setProperty(name.toLatin1().constData(), QVariant(value));
+
+    QTimer::singleShot(0, this, SLOT(loadSensorProperties()));
 }