File indexing completed on 2024-12-22 04:17:28

0001 /***************************************************************************
0002  *                                                                         *
0003  *   copyright : (C) 2007 The University of Toronto                        *
0004  *                   netterfield@astro.utoronto.ca                         *
0005  *                                                                         *
0006  *   This program is free software; you can redistribute it and/or modify  *
0007  *   it under the terms of the GNU General Public License as published by  *
0008  *   the Free Software Foundation; either version 2 of the License, or     *
0009  *   (at your option) any later version.                                   *
0010  *                                                                         *
0011  ***************************************************************************/
0012 
0013 #include "datamanager.h"
0014 #include "databuttonaction.h"
0015 #include "databutton.h"
0016 
0017 #include "dialoglauncher.h"
0018 
0019 #include "document.h"
0020 #include "sessionmodel.h"
0021 #include "datacollection.h"
0022 #include "plotitem.h"
0023 #include "plotaxis.h"
0024 #include "labelitem.h"
0025 
0026 #include "objectstore.h"
0027 #include "dataobject.h"
0028 #include "curve.h"
0029 #include "equation.h"
0030 #include "vector.h"
0031 #include "matrix.h"
0032 #include "histogram.h"
0033 #include "psd.h"
0034 #include "eventmonitorentry.h"
0035 #include "image.h"
0036 #include "csd.h"
0037 #include "basicplugin.h"
0038 #include "updateserver.h"
0039 
0040 #include <QHeaderView>
0041 #include <QToolBar>
0042 #include <QMenu>
0043 #include <QShortcut>
0044 #include <QSortFilterProxyModel>
0045 
0046 #ifdef QT5
0047 #define setResizeMode setSectionResizeMode
0048 #endif
0049 
0050 namespace Kst {
0051 
0052 DataManager::DataManager(QWidget *parent, Document *doc)
0053   : QDialog(parent), _doc(doc), _currentObject(0) {
0054 
0055   setupUi(this);
0056 
0057   MainWindow::setWidgetFlags(this);
0058 
0059   // Setup proxy model for filtering / sorting
0060   _proxyModel = new QSortFilterProxyModel(this);
0061   _proxyModel->setSourceModel(doc->session());
0062   _proxyModel->setFilterKeyColumn(-1); // Filter on all columns by default
0063   _proxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive);
0064   _session->setModel(_proxyModel);
0065 
0066 #if QT_VERSION >= 0x040700
0067   _filterText->setPlaceholderText(tr("Enter your filter here (wildcards allowed)"));
0068 #endif
0069 
0070   connect(_filterText, SIGNAL(textChanged(QString)), _proxyModel, SLOT(setFilterWildcard(QString)));
0071   connect(_caseSensitive, SIGNAL(stateChanged(int)), this, SLOT(setCaseSensitivity(int)));
0072   connect(_filterColumn, SIGNAL(currentIndexChanged(int)), this, SLOT(setFilterColumn(int)));
0073 
0074 
0075   _session->header()->setResizeMode(QHeaderView::ResizeToContents);
0076   _session->setContextMenuPolicy(Qt::CustomContextMenu);
0077   _session->setSortingEnabled(true);
0078   _session->sortByColumn(1); // Sort by type by default
0079   _session->setUniformRowHeights(true);
0080   connect(_session, SIGNAL(customContextMenuRequested(QPoint)),
0081           this, SLOT(showContextMenu(QPoint)));
0082   connect(_session, SIGNAL(doubleClicked(QModelIndex)),
0083           this, SLOT(showEditDialog(QModelIndex)));
0084 
0085   // Simple keyboard shortcut for fast object deletion
0086   _deleteShortcut = new QShortcut(Qt::Key_Delete, this);
0087   connect(_deleteShortcut, SIGNAL(activated()), this, SLOT(deleteObject()));
0088 
0089   _contextMenu = new QMenu(this);
0090 
0091   connect(_purge, SIGNAL(clicked()), this, SLOT(purge()));
0092   connect(_delete, SIGNAL(clicked()), this, SLOT(deleteObject()));
0093   connect(_edit, SIGNAL(clicked()), this, SLOT(showEditDialog()));
0094 }
0095 
0096 DataManager::~DataManager() {
0097   // the data manager is only destroyed at exit, so there is no real
0098   // need to clean up anything...  (though valgrind thinks we really
0099   // ought to delete all of our actions before we exit)
0100 }
0101 
0102 
0103 void DataManager::showEvent(QShowEvent*)
0104 {
0105   _session->header()->setResizeMode(QHeaderView::ResizeToContents);
0106   _session->header()->setStretchLastSection(false);
0107   QApplication::processEvents();
0108   _session->header()->setResizeMode(QHeaderView::Interactive);
0109 }
0110 
0111 
0112 void DataManager::showContextMenu(const QPoint &position) {
0113   QList<QAction *> actions;
0114   if (_session->indexAt(position).isValid()) {
0115     SessionModel *model = static_cast<SessionModel*>(_doc->session());
0116     if (!model->parent(_proxyModel->mapToSource(_session->indexAt(position))).isValid()) {
0117       _currentObject = model->objectList()->at(_proxyModel->mapToSource(_session->indexAt(position)).row());
0118       if (_currentObject) {
0119         QAction *action = new QAction(_currentObject->Name(), this);
0120         action->setEnabled(false);
0121         actions.append(action);
0122 
0123         action = new QAction(tr("Edit"), this);
0124         connect(action, SIGNAL(triggered()), this, SLOT(showEditDialog()));
0125         actions.append(action);
0126 
0127         if (VectorPtr v = kst_cast<Vector>(_currentObject)) {
0128 
0129           action = new QAction(tr("Make Curve"), this);
0130           connect(action, SIGNAL(triggered()), this, SLOT(showCurveDialog()));
0131           actions.append(action);
0132 
0133           action = new QAction(tr("Make Power Spectrum"), this);
0134           connect(action, SIGNAL(triggered()), this, SLOT(showPowerSpectrumDialog()));
0135           actions.append(action);
0136 
0137           action = new QAction(tr("Make Spectrogram"), this);
0138           connect(action, SIGNAL(triggered()), this, SLOT(showCSDDialog()));
0139           actions.append(action);
0140 
0141           action = new QAction(tr("Make Histogram"), this);
0142           connect(action, SIGNAL(triggered()), this, SLOT(showHistogramDialog()));
0143           actions.append(action);
0144 
0145           if (!DataObject::filterPluginList().empty()) {
0146             action = new QAction(tr("Apply Filter"), this);
0147             connect(action, SIGNAL(triggered()), this, SLOT(showFilterDialog()));
0148             actions.append(action);
0149           }
0150         } else if (MatrixPtr m = kst_cast<Matrix>(_currentObject)) {
0151           action = new QAction(tr("Make Image"), this);
0152           connect(action, SIGNAL(triggered()), this, SLOT(showImageDialog()));
0153           actions.append(action);
0154         } else if (RelationPtr r = kst_cast<Relation>(_currentObject)) {
0155 
0156           QMenu *addMenu = new QMenu(this);
0157           QMenu *removeMenu = new QMenu(this);
0158 
0159           foreach (PlotItemInterface *plot, Data::self()->plotList()) {
0160             action = new QAction(plot->plotName(), this);
0161             action->setData(qVariantFromValue(plot));
0162             addMenu->addAction(action);
0163 
0164             PlotItem* plotItem = static_cast<PlotItem*>(plot);
0165             if (plotItem) {
0166               foreach (PlotRenderItem* renderItem, plotItem->renderItems()) {
0167                 if (renderItem->relationList().contains(r)) {
0168                   action = new QAction(plot->plotName(), this);
0169                   action->setData(qVariantFromValue(plot));
0170                   removeMenu->addAction(action);
0171                   break;
0172                 }
0173               }
0174             }
0175           }
0176 
0177           connect(addMenu, SIGNAL(triggered(QAction*)), this, SLOT(addToPlot(QAction*)));
0178           action = new QAction(tr("Add to Plot"), this);
0179 
0180           action->setMenu(addMenu);
0181           actions.append(action);
0182 
0183           connect(removeMenu, SIGNAL(triggered(QAction*)), this, SLOT(removeFromPlot(QAction*)));
0184           action = new QAction(tr("Remove From Plot"), this);
0185           connect(action, SIGNAL(triggered()), this, SLOT(showImageDialog()));
0186 
0187           action->setMenu(removeMenu);
0188           actions.append(action);
0189 
0190           if (!DataObject::fitsPluginList().empty()) {
0191             action = new QAction(tr("Apply Fit"), this);
0192             connect(action, SIGNAL(triggered()), this, SLOT(showFitDialog()));
0193             actions.append(action);
0194           }
0195 
0196           if (!DataObject::filterPluginList().empty()) {
0197             action = new QAction(tr("Apply Filter"), this);
0198             connect(action, SIGNAL(triggered()), this, SLOT(showFilterDialog()));
0199             actions.append(action);
0200           }
0201         }
0202 
0203         // Also add delete action in the menu
0204         action = new QAction(tr("Delete"), this);
0205         connect(action, SIGNAL(triggered()), this, SLOT(deleteObject()));
0206         actions.append(action);
0207       }
0208     } else {
0209       DataObjectPtr dataObject = kst_cast<DataObject>(model->objectList()->at(_proxyModel->mapToSource(_session->indexAt(position)).parent().row()));
0210       if (dataObject) {
0211         if (dataObject->outputVectors().count() > _proxyModel->mapToSource(_session->indexAt(position)).row()) {
0212           _currentObject = dataObject->outputVectors().values()[_proxyModel->mapToSource(_session->indexAt(position)).row()];
0213         } else {
0214           _currentObject = dataObject->outputMatrices().values()[_proxyModel->mapToSource(_session->indexAt(position)).row() - dataObject->outputVectors().count()];
0215         }
0216         if (_currentObject) {
0217           QAction *action = new QAction(_currentObject->Name(), this);
0218           action->setEnabled(false);
0219           actions.append(action);
0220 
0221           if (VectorPtr v = kst_cast<Vector>(_currentObject)) {
0222             action = new QAction(tr("Make Curve"), this);
0223             connect(action, SIGNAL(triggered()), this, SLOT(showCurveDialog()));
0224             actions.append(action);
0225 
0226             action = new QAction(tr("Make Power Spectrum"), this);
0227             connect(action, SIGNAL(triggered()), this, SLOT(showPowerSpectrumDialog()));
0228             actions.append(action);
0229 
0230             action = new QAction(tr("Make Spectrogram"), this);
0231             connect(action, SIGNAL(triggered()), this, SLOT(showCSDDialog()));
0232             actions.append(action);
0233 
0234             action = new QAction(tr("Make Histogram"), this);
0235             connect(action, SIGNAL(triggered()), this, SLOT(showHistogramDialog()));
0236             actions.append(action);
0237 
0238             if (!DataObject::filterPluginList().empty()) {
0239               action = new QAction(tr("Apply Filter"), this);
0240               connect(action, SIGNAL(triggered()), this, SLOT(showFilterDialog()));
0241               actions.append(action);
0242             }
0243 
0244           } else if (MatrixPtr m = kst_cast<Matrix>(_currentObject)) {
0245             action = new QAction(tr("Make Image"), this);
0246             connect(action, SIGNAL(triggered()), this, SLOT(showImageDialog()));
0247             actions.append(action);
0248           }
0249         }
0250       }
0251     }
0252   }
0253   if (actions.count() > 0)
0254       QMenu::exec(actions, _session->mapToGlobal(position));
0255 }
0256 
0257 void DataManager::showEditDialog(QModelIndex qml) {
0258   if (!qml.parent().isValid()) { // don't edit slave objects
0259     //SessionModel *model = static_cast<SessionModel*>(_doc->session());
0260 
0261     //_currentObject = model->objectList()->at(_proxyModel->mapToSource(qml).row());
0262 
0263     showEditDialog(_proxyModel->mapToSource(qml).row());
0264   }
0265 }
0266 
0267 
0268 void DataManager::showEditDialog() {
0269 
0270   if (_session->selectionModel()->selectedIndexes().size()<1) {
0271     return;
0272   }
0273 
0274   QModelIndex qml = _session->selectionModel()->selectedIndexes()[0];
0275 
0276   if (qml.parent().isValid()) { // don't edit slave objects.
0277     return;
0278   }
0279 
0280   int row = _proxyModel->mapToSource(qml).row(); // Single selection mode => only one selected index
0281 
0282   showEditDialog(row);
0283 }
0284 
0285 
0286 void DataManager::showEditDialog(int row) {
0287   SessionModel *model = static_cast<SessionModel*>(_doc->session());
0288   if ((row < 0) || (row >=model->objectList()->size())) {
0289     return;
0290   }
0291   DialogLauncher::self()->showObjectDialog(model->objectList()->at(row));
0292 }
0293 
0294 
0295 void DataManager::showVectorDialog() {
0296   QString tmp;
0297   DialogLauncher::self()->showVectorDialog(tmp);
0298 }
0299 
0300 
0301 void DataManager::showMatrixDialog() {
0302   QString tmp;
0303   DialogLauncher::self()->showMatrixDialog(tmp);
0304 }
0305 
0306 
0307 void DataManager::showScalarDialog() {
0308   QString scalarName;
0309   DialogLauncher::self()->showScalarDialog(scalarName);
0310 }
0311 
0312 
0313 void DataManager::showStringDialog() {
0314   QString stringName;
0315   DialogLauncher::self()->showStringDialog(stringName);
0316 }
0317 
0318 
0319 void DataManager::showEventMonitorDialog() {
0320   DialogLauncher::self()->showEventMonitorDialog();
0321 }
0322 
0323 
0324 void DataManager::showEquationDialog() {
0325   DialogLauncher::self()->showEquationDialog();
0326 }
0327 
0328 
0329 void DataManager::showCurveDialog() {
0330   if (VectorPtr vector = kst_cast<Vector>(_currentObject)) {
0331     DialogLauncher::self()->showCurveDialog(0, vector);
0332   } else {
0333     DialogLauncher::self()->showCurveDialog();
0334   }
0335 }
0336 
0337 
0338 void DataManager::showCSDDialog() {
0339   if (VectorPtr vector = kst_cast<Vector>(_currentObject)) {
0340     DialogLauncher::self()->showCSDDialog(0, vector);
0341   } else {
0342     DialogLauncher::self()->showCSDDialog();
0343   }
0344 }
0345 
0346 
0347 void DataManager::showPowerSpectrumDialog() {
0348   if (VectorPtr vector = kst_cast<Vector>(_currentObject)) {
0349     DialogLauncher::self()->showPowerSpectrumDialog(0, vector);
0350   } else {
0351     DialogLauncher::self()->showPowerSpectrumDialog();
0352   }
0353 }
0354 
0355 
0356 void DataManager::showHistogramDialog() {
0357   if (VectorPtr vector = kst_cast<Vector>(_currentObject)) {
0358     DialogLauncher::self()->showHistogramDialog(0, vector);
0359   } else {
0360     DialogLauncher::self()->showHistogramDialog();
0361   }
0362 }
0363 
0364 
0365 void DataManager::showImageDialog() {
0366   if (MatrixPtr matrix = kst_cast<Matrix>(_currentObject)) {
0367     DialogLauncher::self()->showImageDialog(0, matrix);
0368   } else {
0369     DialogLauncher::self()->showImageDialog();
0370   }
0371 }
0372 
0373 
0374 void DataManager::showPluginDialog(QString &pluginName) {
0375   if (VectorPtr vector = kst_cast<Vector>(_currentObject)) {
0376     DialogLauncher::self()->showBasicPluginDialog(pluginName, 0, vector);
0377   } else if (CurvePtr curve = kst_cast<Curve>(_currentObject)) {
0378     DialogLauncher::self()->showBasicPluginDialog(pluginName, 0, curve->xVector(), curve->yVector());
0379   } else {
0380     DialogLauncher::self()->showBasicPluginDialog(pluginName);
0381   }
0382 }
0383 
0384 
0385 void DataManager::showFilterDialog() {
0386   showPluginDialog(DataObject::filterPluginList().first());
0387 }
0388 
0389 
0390 void DataManager::showFitDialog() {
0391   showPluginDialog(DataObject::fitsPluginList().first());
0392 }
0393 
0394 
0395 void DataManager::deleteObject() {
0396   SessionModel *model = static_cast<SessionModel*>(_doc->session());
0397 
0398   if (_session->selectionModel()->selectedIndexes().size()<1) {
0399     return;
0400   }
0401 
0402   int row = _proxyModel->mapToSource(_session->selectionModel()->selectedIndexes()[0]).row(); // Single selection mode => only one selected index
0403   _currentObject = model->objectList()->at(row);
0404   if (RelationPtr relation = kst_cast<Relation>(_currentObject)) {
0405     Data::self()->removeCurveFromPlots(relation);
0406     _doc->objectStore()->removeObject(relation);
0407   } else if (DataObjectPtr dataObject = kst_cast<DataObject>(_currentObject)) {
0408     _doc->objectStore()->removeObject(dataObject);
0409   } else if (PrimitivePtr primitive = kst_cast<Primitive>(_currentObject)) {
0410     _doc->objectStore()->removeObject(primitive);
0411   } else if (DataSourcePtr datasource = kst_cast<DataSource>(_currentObject)) {
0412     _doc->objectStore()->removeObject(datasource);
0413   }
0414   _currentObject = 0;
0415   UpdateServer::self()->requestUpdateSignal();
0416 
0417   // Now select the next item
0418   _session->selectionModel()->select(_proxyModel->mapFromSource(model->index(row,0)), QItemSelectionModel::Select);
0419   // Cleanup and return
0420   _doc->objectStore()->cleanUpDataSourceList();
0421 }
0422 
0423 void DataManager::addToPlot(QAction* action) {
0424   PlotItem* plotItem = static_cast<PlotItem*>(action->data().value<PlotItemInterface*>());
0425   RelationPtr relation = kst_cast<Relation>(_currentObject);
0426   if (plotItem && relation) {
0427     PlotRenderItem *renderItem = plotItem->renderItem(PlotRenderItem::Cartesian);
0428     renderItem->addRelation(kst_cast<Relation>(relation));
0429     plotItem->update();
0430   }
0431 }
0432 
0433 
0434 void DataManager::removeFromPlot(QAction* action) {
0435   bool plotUpdated = false;
0436 
0437   PlotItem* plotItem = static_cast<PlotItem*>(action->data().value<PlotItemInterface*>());
0438   RelationPtr relation = kst_cast<Relation>(_currentObject);
0439   if (plotItem && relation) {
0440     foreach (PlotRenderItem* renderItem, plotItem->renderItems()) {
0441       if (renderItem->relationList().contains(relation)) {
0442         renderItem->removeRelation(relation);
0443         plotUpdated = true;
0444       }
0445     }
0446     if (plotUpdated) {
0447       plotItem->update();
0448     }
0449   }
0450 }
0451 
0452 // search through all the objects to see what is a dependency of anything shown.
0453 // FIXME: this is very fragile - objects use objects in all sorts of ways,
0454 // all which have to be listed here.
0455 void DataManager::setUsedFlags() {
0456   _doc->objectStore()->clearUsedFlags();
0457 
0458   // for each relation used in an unhidden plot mark 'used' - O(N)
0459   QList<PlotItem*> plotlist = ViewItem::getItems<PlotItem>();
0460   foreach (PlotItem *plot, plotlist) {
0461     if (plot->isVisible()) {
0462       foreach (PlotRenderItem *renderer, plot->renderItems()) {
0463         foreach (RelationPtr relation, renderer->relationList()) {
0464           relation->setUsed(true);
0465         }
0466       }
0467       if (plot->xAxis()->axisPlotMarkers().isCurveSource()) {
0468         plot->xAxis()->axisPlotMarkers().curve()->setUsed(true);
0469       }
0470       if (plot->yAxis()->axisPlotMarkers().isCurveSource()) {
0471         plot->yAxis()->axisPlotMarkers().curve()->setUsed(true);
0472       }
0473       if (plot->xAxis()->axisPlotMarkers().isVectorSource()) {
0474         plot->xAxis()->axisPlotMarkers().vector()->setUsed(true);
0475       }
0476       if (plot->yAxis()->axisPlotMarkers().isVectorSource()) {
0477         plot->yAxis()->axisPlotMarkers().vector()->setUsed(true);
0478       }
0479     }
0480   }
0481 
0482   QList<LabelItem*> labels = ViewItem::getItems<LabelItem>();
0483   foreach (LabelItem * label, labels) {
0484     if (label->_labelRc) {
0485       foreach (Primitive* primitive, label->_labelRc->_refObjects) {
0486         primitive->setUsed(true);
0487       }
0488     }
0489   }
0490 
0491   // for each primitive used by a relation mark 'used' - O(N)
0492   ObjectList<Relation> relationList = _doc->objectStore()->getObjects<Relation>();
0493   foreach (RelationPtr object, relationList) {
0494     object->readLock();
0495     //set used all input and output primitives
0496     foreach (VectorPtr v, object->inputVectors()) {
0497       v->setUsed(true);
0498     }
0499     foreach (VectorPtr v, object->outputVectors()) {
0500       v->setUsed(true);
0501     }
0502     foreach (ScalarPtr s, object->inputScalars()) {
0503       s->setUsed(true);
0504     }
0505     foreach (ScalarPtr s, object->outputScalars()) {
0506       s->setUsed(true);
0507     }
0508     foreach (StringPtr s, object->inputStrings()) {
0509       s->setUsed(true);
0510     }
0511     foreach (StringPtr s, object->outputStrings()) {
0512       s->setUsed(true);
0513     }
0514     foreach (MatrixPtr m, object->inputMatrices()) {
0515       m->setUsed(true);
0516     }
0517     foreach (MatrixPtr m, object->outputMatrices()) {
0518       m->setUsed(true);
0519     }
0520     object->unlock();
0521   }
0522 
0523 
0524   ObjectList<DataObject> dataObjectList = _doc->objectStore()->getObjects<DataObject>();
0525   foreach (DataObjectPtr object, dataObjectList) {
0526     object->readLock();
0527     //set used all input and output primitives
0528     foreach (PrimitivePtr p, object->inputPrimitives()) {
0529       p->setUsed(true);
0530     }
0531     object->unlock();
0532   }
0533 }
0534 
0535 void DataManager::purge() {
0536   do {
0537     setUsedFlags();
0538   } while (_doc->objectStore()->deleteUnsetUsedFlags());
0539   _doc->objectStore()->cleanUpDataSourceList();
0540   UpdateServer::self()->requestUpdateSignal();
0541   _session->reset();
0542 }
0543 
0544 void DataManager::setFilterColumn(int column) {
0545   _proxyModel->setFilterKeyColumn(column-1);
0546 }
0547 
0548 void DataManager::setCaseSensitivity(int state) {
0549   if (state) {
0550     _proxyModel->setFilterCaseSensitivity(Qt::CaseSensitive);
0551   } else {
0552     _proxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive);
0553   }
0554 }
0555 
0556 }
0557 // vim: ts=2 sw=2 et