qtmobility/examples/sensors/sensor_explorer/explorer.cpp
changeset 4 90517678cc4f
parent 1 2b40d63a9c3d
child 5 453da2cfceef
equal deleted inserted replaced
1:2b40d63a9c3d 4:90517678cc4f
    48 
    48 
    49 QTM_USE_NAMESPACE
    49 QTM_USE_NAMESPACE
    50 
    50 
    51 Explorer::Explorer(QWidget *parent)
    51 Explorer::Explorer(QWidget *parent)
    52     : QMainWindow(parent)
    52     : QMainWindow(parent)
    53 {
    53     , m_sensor(0)
    54     setupUi(this);
    54     , ignoreItemChanged(false)
       
    55 {
       
    56     ui.setupUi(this);
       
    57 #ifdef MAEMO5
       
    58     ui.label->hide();
       
    59 #endif
    55     // Clear out example data from the .ui file
    60     // Clear out example data from the .ui file
    56     m_sensors->clear();
    61     ui.sensors->clear();
       
    62     clearSensorProperties();
    57     clearReading();
    63     clearReading();
    58     // We need to know when this widget resizes
       
    59     // so we can resize the columns
       
    60     m_reading->installEventFilter(this);
       
    61 }
    64 }
    62 
    65 
    63 Explorer::~Explorer()
    66 Explorer::~Explorer()
    64 {
    67 {
    65 }
    68 }
    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