@@ -105,6 +105,11 @@ void MainWindow::init()
105105 ui->viewMenu ->actions ().at (0 )->setIcon (QIcon (" :/icons/log_dock" ));
106106 ui->viewDBToolbarAction ->setChecked (!ui->toolbarDB ->isHidden ());
107107
108+ // Plot view menu
109+ ui->viewMenu ->insertAction (ui->viewDBToolbarAction , ui->dockPlot ->toggleViewAction ());
110+ ui->viewMenu ->actions ().at (1 )->setShortcut (QKeySequence (tr (" Ctrl+P" )));
111+ ui->viewMenu ->actions ().at (1 )->setIcon (QIcon (" :/icons/log_dock" ));
112+
108113 // Set statusbar fields
109114 statusEncodingLabel = new QLabel (ui->statusbar );
110115 statusEncodingLabel->setEnabled (false );
@@ -123,6 +128,7 @@ void MainWindow::init()
123128 restoreGeometry (PreferencesDialog::getSettingsValue (" MainWindow" , " geometry" ).toByteArray ());
124129 restoreState (PreferencesDialog::getSettingsValue (" MainWindow" , " windowState" ).toByteArray ());
125130 ui->comboLogSubmittedBy ->setCurrentIndex (ui->comboLogSubmittedBy ->findText (PreferencesDialog::getSettingsValue (" SQLLogDock" , " Log" ).toString ()));
131+ ui->splitterForPlot ->restoreState (PreferencesDialog::getSettingsValue (" PlotDock" , " splitterSize" ).toByteArray ());
126132
127133 // Set other window settings
128134 setAcceptDrops (true );
@@ -308,6 +314,9 @@ void MainWindow::populateTable( const QString & tablename)
308314 if (editWin)
309315 editWin->reset ();
310316
317+ // update plot
318+ updatePlot (m_browseTableModel);
319+
311320 QApplication::restoreOverrideCursor ();
312321}
313322
@@ -363,6 +372,7 @@ void MainWindow::closeEvent( QCloseEvent* event )
363372 PreferencesDialog::setSettingsValue (" MainWindow" , " geometry" , saveGeometry ());
364373 PreferencesDialog::setSettingsValue (" MainWindow" , " windowState" , saveState ());
365374 PreferencesDialog::setSettingsValue (" SQLLogDock" , " Log" , ui->comboLogSubmittedBy ->currentText ());
375+ PreferencesDialog::setSettingsValue (" PlotDock" , " splitterSize" , ui->splitterForPlot ->saveState ());
366376 clearCompleterModelsFields ();
367377 QMainWindow::closeEvent (event);
368378}
@@ -699,6 +709,7 @@ void MainWindow::executeQuery()
699709 }
700710 } while ( tail && *tail != 0 && (sql3status == SQLITE_OK || sql3status == SQLITE_DONE));
701711 sqlWidget->finishExecution (statusMessage);
712+ updatePlot (sqlWidget->getModel ());
702713
703714 if (!modified && !wasdirty)
704715 db.revert (); // better rollback, if the logic is not enough we can tune it.
@@ -1308,3 +1319,157 @@ void MainWindow::httpresponse(QNetworkReply *reply)
13081319 }
13091320 }
13101321}
1322+
1323+ namespace {
1324+ /* !
1325+ * \brief guessdatatype try to parse the first 10 rows and decide the datatype
1326+ * \param model model to check the data
1327+ * \param column index of the column to check
1328+ * \return the guessed datatype
1329+ */
1330+ QVariant::Type guessdatatype (SqliteTableModel* model, int column)
1331+ {
1332+ QVariant::Type type = QVariant::Invalid;
1333+ for (int i = 0 ; i < std::min (10 , model->rowCount ()) && type != QVariant::String; ++i)
1334+ {
1335+ QVariant data = model->data (model->index (i, column));
1336+ if (data.convert (QVariant::Double))
1337+ {
1338+ type = QVariant::Double;
1339+ }
1340+ else
1341+ {
1342+ QString s = model->data (model->index (i, column)).toString ();
1343+ QDate d = QDate::fromString (s, Qt::ISODate);
1344+ if (d.isValid ())
1345+ type = QVariant::DateTime;
1346+ else
1347+ type = QVariant::String;
1348+ }
1349+
1350+ }
1351+ return type;
1352+ }
1353+ }
1354+
1355+ void MainWindow::updatePlot (SqliteTableModel *model, bool update)
1356+ {
1357+ // add columns to x/y seleciton tree widget
1358+ if (update)
1359+ {
1360+ disconnect (ui->treePlotColumns , SIGNAL (itemChanged (QTreeWidgetItem*,int )),
1361+ this ,SLOT (on_treePlotColumns_itemChanged (QTreeWidgetItem*,int )));
1362+
1363+ m_currentPlotModel = model;
1364+ ui->treePlotColumns ->clear ();
1365+
1366+ for (int i = 0 ; i < model->columnCount (); ++i)
1367+ {
1368+ QVariant::Type columntype = guessdatatype (model, i);
1369+ if (columntype != QVariant::String && columntype != QVariant::Invalid)
1370+ {
1371+ QTreeWidgetItem* columnitem = new QTreeWidgetItem (ui->treePlotColumns );
1372+ // maybe i make this more complicated than i should
1373+ // but store the model column index in the first 16 bit and the type
1374+ // in the other 16 bits
1375+ uint itemdata = 0 ;
1376+ itemdata = i << 16 ;
1377+ itemdata |= columntype;
1378+ columnitem->setData (0 , Qt::UserRole, itemdata);
1379+
1380+ columnitem->setText (0 , model->headerData (i, Qt::Horizontal).toString ());
1381+ columnitem->setCheckState (1 , Qt::Unchecked);
1382+ columnitem->setCheckState (2 , Qt::Unchecked);
1383+ ui->treePlotColumns ->addTopLevelItem (columnitem);
1384+ }
1385+ }
1386+
1387+ ui->plotWidget ->yAxis ->setLabel (" Y" );
1388+ ui->plotWidget ->xAxis ->setLabel (" X" );
1389+ connect (ui->treePlotColumns , SIGNAL (itemChanged (QTreeWidgetItem*,int )),this ,SLOT (on_treePlotColumns_itemChanged (QTreeWidgetItem*,int )));
1390+ }
1391+
1392+ // search for the x axis select
1393+ QTreeWidgetItem* xitem = 0 ;
1394+ for (int i = 0 ; i < ui->treePlotColumns ->topLevelItemCount (); ++i)
1395+ {
1396+ xitem = ui->treePlotColumns ->topLevelItem (i);
1397+ if (xitem->checkState (2 ) == Qt::Checked)
1398+ break ;
1399+
1400+ xitem = 0 ;
1401+ }
1402+
1403+ QStringList yAxisLabels;
1404+ QVector<QColor> colors;
1405+ colors << Qt::blue << Qt::red << Qt::green << Qt::darkYellow << Qt::darkCyan << Qt::darkGray;
1406+
1407+ ui->plotWidget ->clearGraphs ();
1408+ if (xitem)
1409+ {
1410+ uint xitemdata = xitem->data (0 , Qt::UserRole).toUInt ();
1411+ int x = xitemdata >> 16 ;
1412+ int xtype = xitemdata & (uint)0xFF ;
1413+
1414+
1415+ // check if we have a x axis with datetime data
1416+ if (xtype == QVariant::DateTime)
1417+ {
1418+ ui->plotWidget ->xAxis ->setTickLabelType (QCPAxis::ltDateTime);
1419+ ui->plotWidget ->xAxis ->setDateTimeFormat (" yyyy-mm-dd" );
1420+ }
1421+ else
1422+ {
1423+ ui->plotWidget ->xAxis ->setTickLabelType (QCPAxis::ltNumber);
1424+ }
1425+
1426+ // add graph for each selected y axis
1427+ for (int i = 0 ; i < ui->treePlotColumns ->topLevelItemCount (); ++i)
1428+ {
1429+ QTreeWidgetItem* item = ui->treePlotColumns ->topLevelItem (i);
1430+ if (item->checkState ((1 )) == Qt::Checked && ui->plotWidget ->graphCount () < colors.size ())
1431+ {
1432+ uint itemdata = item->data (0 , Qt::UserRole).toUInt ();
1433+ int column = itemdata >> 16 ;
1434+ QCPGraph* graph = ui->plotWidget ->addGraph ();
1435+
1436+ int y = column;
1437+
1438+ graph->setPen (QPen (colors[y]));
1439+
1440+ QVector<double > xdata (model->rowCount ()), ydata (model->rowCount ());
1441+ for (int i = 0 ; i < model->rowCount (); ++i)
1442+ {
1443+ // convert x type axis if it's datetime
1444+ if (xtype == QVariant::DateTime)
1445+ {
1446+ QString s = model->data (model->index (i, x)).toString ();
1447+ QDateTime d = QDateTime::fromString (s, Qt::ISODate);
1448+ xdata[i] = d.toTime_t ();
1449+ }
1450+ else
1451+ {
1452+ xdata[i] = model->data (model->index (i, x)).toDouble ();
1453+ }
1454+
1455+ ydata[i] = model->data (model->index (i, y)).toDouble ();
1456+ }
1457+ graph->setData (xdata, ydata);
1458+ graph->setLineStyle (QCPGraph::lsLine);
1459+ graph->setScatterStyle (QCPScatterStyle (QCPScatterStyle::ssDisc, 5 ));
1460+ yAxisLabels << model->headerData (y, Qt::Horizontal).toString ();
1461+ graph->rescaleAxes ();
1462+ }
1463+ }
1464+
1465+ // set axis labels
1466+ ui->plotWidget ->xAxis ->setLabel (model->headerData (x, Qt::Horizontal).toString ());
1467+ ui->plotWidget ->yAxis ->setLabel (yAxisLabels.join (" |" ));
1468+ }
1469+ ui->plotWidget ->replot ();
1470+ }
1471+
1472+ void MainWindow::on_treePlotColumns_itemChanged (QTreeWidgetItem *item, int column)
1473+ {
1474+ updatePlot (m_currentPlotModel, false );
1475+ }
0 commit comments