annotate widgets/ModelDataTableDialog.cpp @ 1569:b33b0b06133e

Merge from branch csv-export-dialog
author Chris Cannam
date Tue, 14 Jan 2020 15:48:44 +0000
parents 0ca4ca37809e
children
rev   line source
Chris@392 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@392 2
Chris@392 3 /*
Chris@392 4 Sonic Visualiser
Chris@392 5 An audio file viewer and annotation editor.
Chris@392 6 Centre for Digital Music, Queen Mary, University of London.
Chris@392 7 This file copyright 2008 QMUL.
Chris@392 8
Chris@392 9 This program is free software; you can redistribute it and/or
Chris@392 10 modify it under the terms of the GNU General Public License as
Chris@392 11 published by the Free Software Foundation; either version 2 of the
Chris@392 12 License, or (at your option) any later version. See the file
Chris@392 13 COPYING included with this distribution for more information.
Chris@392 14 */
Chris@392 15
Chris@392 16 #include "ModelDataTableDialog.h"
Chris@392 17
Chris@392 18 #include "data/model/ModelDataTableModel.h"
Chris@395 19 #include "data/model/TabularModel.h"
Chris@398 20 #include "data/model/Model.h"
Chris@392 21
Chris@393 22 #include "CommandHistory.h"
Chris@399 23 #include "IconLoader.h"
Chris@393 24
Chris@392 25 #include <QTableView>
Chris@552 26 #include <QLineEdit>
Chris@392 27 #include <QGridLayout>
Chris@552 28 #include <QLabel>
Chris@392 29 #include <QGroupBox>
Chris@392 30 #include <QDialogButtonBox>
Chris@392 31 #include <QHeaderView>
Chris@392 32 #include <QApplication>
Chris@1478 33 #include <QScreen>
Chris@399 34 #include <QAction>
Chris@399 35 #include <QToolBar>
Chris@392 36
Chris@393 37 #include <iostream>
Chris@393 38
Chris@1536 39 //#define DEBUG_MODEL_DATA_TABLE_DIALOG 1
Chris@1536 40
Chris@1479 41 ModelDataTableDialog::ModelDataTableDialog(ModelId tabularModelId,
Chris@404 42 QString title, QWidget *parent) :
Chris@400 43 QMainWindow(parent),
Chris@401 44 m_currentRow(0),
Chris@404 45 m_trackPlayback(true)
Chris@392 46 {
Chris@392 47 setWindowTitle(tr("Data Editor"));
Chris@392 48
Chris@404 49 QToolBar *toolbar;
Chris@399 50
Chris@404 51 toolbar = addToolBar(tr("Playback Toolbar"));
Chris@404 52 m_playToolbar = toolbar;
Chris@404 53 toolbar = addToolBar(tr("Play Mode Toolbar"));
Chris@404 54
Chris@399 55 IconLoader il;
Chris@399 56
Chris@402 57 QAction *action = new QAction(il.load("playfollow"), tr("Track Playback"), this);
Chris@402 58 action->setStatusTip(tr("Toggle tracking of playback position"));
Chris@402 59 action->setCheckable(true);
Chris@404 60 action->setChecked(m_trackPlayback);
Chris@402 61 connect(action, SIGNAL(triggered()), this, SLOT(togglePlayTracking()));
Chris@402 62 toolbar->addAction(action);
Chris@402 63
Chris@404 64 toolbar = addToolBar(tr("Edit Toolbar"));
Chris@402 65
Chris@1175 66 action = new QAction(il.load("draw"), tr("Insert New Item"), this);
Chris@399 67 action->setShortcut(tr("Insert"));
Chris@399 68 action->setStatusTip(tr("Insert a new item"));
Chris@399 69 connect(action, SIGNAL(triggered()), this, SLOT(insertRow()));
Chris@399 70 toolbar->addAction(action);
Chris@399 71
Chris@399 72 action = new QAction(il.load("datadelete"), tr("Delete Selected Items"), this);
Chris@399 73 action->setShortcut(tr("Delete"));
Chris@399 74 action->setStatusTip(tr("Delete the selected item or items"));
Chris@400 75 connect(action, SIGNAL(triggered()), this, SLOT(deleteRows()));
Chris@399 76 toolbar->addAction(action);
Chris@399 77
Chris@404 78 CommandHistory::getInstance()->registerToolbar(toolbar);
Chris@404 79
Chris@396 80 QFrame *mainFrame = new QFrame;
Chris@396 81 setCentralWidget(mainFrame);
Chris@396 82
Chris@392 83 QGridLayout *grid = new QGridLayout;
Chris@396 84 mainFrame->setLayout(grid);
Chris@392 85
Chris@392 86 QGroupBox *box = new QGroupBox;
Chris@398 87 if (title != "") {
Chris@398 88 box->setTitle(title);
Chris@398 89 } else {
Chris@398 90 box->setTitle(tr("Data in Layer"));
Chris@398 91 }
Chris@392 92 grid->addWidget(box, 0, 0);
Chris@392 93 grid->setRowStretch(0, 15);
Chris@392 94
Chris@392 95 QGridLayout *subgrid = new QGridLayout;
Chris@392 96 box->setLayout(subgrid);
Chris@392 97
Chris@392 98 subgrid->setSpacing(0);
Chris@392 99 subgrid->setMargin(5);
Chris@392 100
Chris@552 101 subgrid->addWidget(new QLabel(tr("Find:")), 1, 0);
Chris@552 102 subgrid->addWidget(new QLabel(tr(" ")), 1, 1);
Chris@552 103 m_find = new QLineEdit;
Chris@552 104 subgrid->addWidget(m_find, 1, 2);
Chris@552 105 connect(m_find, SIGNAL(textChanged(const QString &)),
Chris@552 106 this, SLOT(searchTextChanged(const QString &)));
Chris@552 107 connect(m_find, SIGNAL(returnPressed()),
Chris@552 108 this, SLOT(searchRepeated()));
Chris@552 109
Chris@392 110 m_tableView = new QTableView;
Chris@552 111 subgrid->addWidget(m_tableView, 0, 0, 1, 3);
Chris@392 112
Chris@395 113 m_tableView->setSortingEnabled(true);
Chris@396 114 m_tableView->sortByColumn(0, Qt::AscendingOrder);
Chris@392 115
Chris@1479 116 m_table = new ModelDataTableModel(tabularModelId);
Chris@392 117 m_tableView->setModel(m_table);
Chris@392 118
Chris@552 119 m_tableView->horizontalHeader()->setStretchLastSection(true);
Chris@552 120
Chris@393 121 connect(m_tableView, SIGNAL(clicked(const QModelIndex &)),
Chris@393 122 this, SLOT(viewClicked(const QModelIndex &)));
Chris@393 123 connect(m_tableView, SIGNAL(pressed(const QModelIndex &)),
Chris@393 124 this, SLOT(viewPressed(const QModelIndex &)));
Chris@400 125 connect(m_tableView->selectionModel(),
Chris@400 126 SIGNAL(currentChanged(const QModelIndex &, const QModelIndex &)),
Chris@400 127 this,
Chris@400 128 SLOT(currentChanged(const QModelIndex &, const QModelIndex &)));
Chris@400 129 connect(m_table, SIGNAL(addCommand(Command *)),
Chris@400 130 this, SLOT(addCommand(Command *)));
Chris@401 131 connect(m_table, SIGNAL(currentChanged(const QModelIndex &)),
Chris@401 132 this, SLOT(currentChangedThroughResort(const QModelIndex &)));
Chris@428 133 connect(m_table, SIGNAL(modelRemoved()),
Chris@428 134 this, SLOT(modelRemoved()));
Chris@393 135
Chris@392 136 QDialogButtonBox *bb = new QDialogButtonBox(QDialogButtonBox::Close);
Chris@396 137 connect(bb, SIGNAL(rejected()), this, SLOT(close()));
Chris@392 138 grid->addWidget(bb, 2, 0);
Chris@392 139 grid->setRowStretch(2, 0);
Chris@392 140
Chris@1478 141 QScreen *screen = QGuiApplication::primaryScreen();
Chris@1478 142 QRect available = screen->availableGeometry();
Chris@392 143
Chris@392 144 int width = available.width() / 3;
Chris@392 145 int height = available.height() / 2;
Chris@392 146 if (height < 370) {
Chris@392 147 if (available.height() > 500) height = 370;
Chris@392 148 }
Chris@552 149 if (width < 650) {
Chris@552 150 if (available.width() > 750) width = 650;
Chris@552 151 else if (width < 500) {
Chris@552 152 if (available.width() > 650) width = 500;
Chris@552 153 }
Chris@392 154 }
Chris@392 155
Chris@392 156 resize(width, height);
Chris@392 157 }
Chris@392 158
Chris@392 159 ModelDataTableDialog::~ModelDataTableDialog()
Chris@392 160 {
Chris@392 161 delete m_table;
Chris@392 162 }
Chris@392 163
Chris@393 164 void
Chris@908 165 ModelDataTableDialog::userScrolledToFrame(sv_frame_t frame)
Chris@393 166 {
Chris@1536 167 #ifdef DEBUG_MODEL_DATA_TABLE_DIALOG
Chris@1536 168 SVDEBUG << "ModelDataTableDialog::userScrolledToFrame " << frame << endl;
Chris@1536 169 #endif
Chris@1536 170
Chris@1536 171 // The table may contain more than one row with the same frame. If
Chris@1536 172 // our current row has the same frame as the one passed in, we
Chris@1536 173 // should do nothing - this avoids e.g. the situation where the
Chris@1536 174 // user clicks on the second of two equal-framed rows, we fire
Chris@1536 175 // scrollToFrame() from viewClicked(), that calls back here, and
Chris@1536 176 // we end up switching the selection to the first of the two rows
Chris@1536 177 // instead of the one the user clicked on.
Chris@1536 178
Chris@1536 179 if (m_table->getFrameForModelIndex(m_table->index(m_currentRow, 0)) ==
Chris@1536 180 frame) {
Chris@1536 181 #ifdef DEBUG_MODEL_DATA_TABLE_DIALOG
Chris@1536 182 SVDEBUG << "ModelDataTableDialog::userScrolledToFrame: Already have this frame current; calling makeCurrent" << endl;
Chris@1536 183 #endif
Chris@1536 184 return;
Chris@1536 185 }
Chris@1536 186
Chris@401 187 QModelIndex index = m_table->getModelIndexForFrame(frame);
Chris@401 188 makeCurrent(index.row());
Chris@401 189 }
Chris@401 190
Chris@401 191 void
Chris@908 192 ModelDataTableDialog::playbackScrolledToFrame(sv_frame_t frame)
Chris@401 193 {
Chris@401 194 if (m_trackPlayback) {
Chris@401 195 QModelIndex index = m_table->getModelIndexForFrame(frame);
Chris@401 196 makeCurrent(index.row());
Chris@401 197 }
Chris@401 198 }
Chris@401 199
Chris@401 200 void
Chris@552 201 ModelDataTableDialog::searchTextChanged(const QString &text)
Chris@552 202 {
Chris@552 203 QModelIndex mi = m_table->findText(text);
Chris@552 204 if (mi.isValid()) {
Chris@552 205 makeCurrent(mi.row());
Chris@552 206 m_tableView->selectionModel()->setCurrentIndex
Chris@552 207 (mi, QItemSelectionModel::ClearAndSelect);
Chris@552 208 }
Chris@552 209 }
Chris@552 210
Chris@552 211 void
Chris@552 212 ModelDataTableDialog::searchRepeated()
Chris@552 213 {
Chris@552 214 QModelIndex mi = m_table->findText(m_find->text());
Chris@552 215 if (mi.isValid()) {
Chris@552 216 makeCurrent(mi.row());
Chris@552 217 m_tableView->selectionModel()->setCurrentIndex
Chris@552 218 (mi, QItemSelectionModel::ClearAndSelect);
Chris@552 219 }
Chris@552 220 }
Chris@552 221
Chris@552 222 void
Chris@401 223 ModelDataTableDialog::makeCurrent(int row)
Chris@401 224 {
Chris@1271 225 if (m_table->rowCount() == 0 ||
Chris@1271 226 row >= m_table->rowCount() ||
Chris@1271 227 row < 0) {
Chris@1271 228 return;
Chris@1271 229 }
Chris@1271 230
Chris@401 231 int rh = m_tableView->height() / m_tableView->rowHeight(0);
Chris@404 232 int topRow = row - rh/4;
Chris@401 233 if (topRow < 0) topRow = 0;
Chris@404 234
Chris@404 235 // should only scroll if the desired row is not currently visible
Chris@404 236
Chris@404 237 // should only select if no part of the desired row is currently selected
Chris@404 238
Chris@682 239 // cerr << "rh = " << rh << ", row = " << row << ", scrolling to "
Chris@682 240 // << topRow << endl;
Chris@404 241
Chris@404 242 int pos = m_tableView->rowViewportPosition(row);
Chris@404 243
Chris@404 244 if (pos < 0 || pos >= m_tableView->height() - rh) {
Chris@404 245 m_tableView->scrollTo(m_table->index(topRow, 0));
Chris@404 246 }
Chris@404 247
Chris@404 248 bool haveRowSelected = false;
Chris@404 249 for (int i = 0; i < m_table->columnCount(); ++i) {
Chris@404 250 if (m_tableView->selectionModel()->isSelected(m_table->index(row, i))) {
Chris@404 251 haveRowSelected = true;
Chris@404 252 break;
Chris@404 253 }
Chris@404 254 }
Chris@404 255
Chris@404 256 if (!haveRowSelected) {
Chris@404 257 m_tableView->selectionModel()->setCurrentIndex
Chris@404 258 (m_table->index(row, 0),
Chris@404 259 QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows);
Chris@404 260 }
Chris@393 261 }
Chris@393 262
Chris@393 263 void
Chris@393 264 ModelDataTableDialog::viewClicked(const QModelIndex &index)
Chris@393 265 {
Chris@1536 266 #ifdef DEBUG_MODEL_DATA_TABLE_DIALOG
Chris@1536 267 SVDEBUG << "ModelDataTableDialog::viewClicked: " << index.row() << ", " << index.column() << endl;
Chris@1536 268 #endif
Chris@1536 269
Chris@394 270 emit scrollToFrame(m_table->getFrameForModelIndex(index));
Chris@393 271 }
Chris@393 272
Chris@393 273 void
Chris@807 274 ModelDataTableDialog::viewPressed(const QModelIndex &)
Chris@393 275 {
Chris@1536 276 #ifdef DEBUG_MODEL_DATA_TABLE_DIALOG
Chris@1536 277 SVDEBUG << "ModelDataTableDialog::viewPressed: " << index.row() << ", " << index.column() << endl;
Chris@1536 278 #endif
Chris@393 279 }
Chris@393 280
Chris@393 281 void
Chris@400 282 ModelDataTableDialog::currentChanged(const QModelIndex &current,
Chris@1272 283 const QModelIndex &previous)
Chris@399 284 {
Chris@1536 285 #ifdef DEBUG_MODEL_DATA_TABLE_DIALOG
Chris@1272 286 SVDEBUG << "ModelDataTableDialog::currentChanged: from "
Chris@1272 287 << previous.row() << ", " << previous.column()
Chris@1272 288 << " to " << current.row() << ", " << current.column()
Chris@1272 289 << endl;
Chris@1538 290 #else
Chris@1538 291 (void)previous; // unused
Chris@1536 292 #endif
Chris@400 293 m_currentRow = current.row();
Chris@401 294 m_table->setCurrentRow(m_currentRow);
Chris@399 295 }
Chris@399 296
Chris@399 297 void
Chris@400 298 ModelDataTableDialog::insertRow()
Chris@399 299 {
Chris@400 300 m_table->insertRow(m_currentRow);
Chris@400 301 }
Chris@400 302
Chris@400 303 void
Chris@400 304 ModelDataTableDialog::deleteRows()
Chris@400 305 {
Chris@1272 306 std::set<int> selectedRows;
Chris@1272 307 if (m_tableView->selectionModel()->hasSelection()) {
Chris@1272 308 for (const auto &ix: m_tableView->selectionModel()->selectedIndexes()) {
Chris@1272 309 selectedRows.insert(ix.row());
Chris@1272 310 }
Chris@1272 311 }
Chris@1272 312 // Remove rows in reverse order, so as not to pull the rug from
Chris@1272 313 // under our own feet
Chris@1272 314 for (auto ri = selectedRows.rbegin(); ri != selectedRows.rend(); ++ri) {
Chris@1536 315 #ifdef DEBUG_MODEL_DATA_TABLE_DIALOG
Chris@1272 316 SVDEBUG << "ModelDataTableDialog: removing row " << *ri << endl;
Chris@1536 317 #endif
Chris@1272 318 m_table->removeRow(*ri);
Chris@400 319 }
Chris@399 320 }
Chris@399 321
Chris@399 322 void
Chris@399 323 ModelDataTableDialog::editRow()
Chris@399 324 {
Chris@399 325 }
Chris@399 326
Chris@399 327 void
Chris@400 328 ModelDataTableDialog::addCommand(Command *command)
Chris@393 329 {
Chris@397 330 CommandHistory::getInstance()->addCommand(command, false, true);
Chris@393 331 }
Chris@393 332
Chris@401 333 void
Chris@402 334 ModelDataTableDialog::togglePlayTracking()
Chris@402 335 {
Chris@402 336 m_trackPlayback = !m_trackPlayback;
Chris@402 337 }
Chris@402 338
Chris@402 339 void
Chris@401 340 ModelDataTableDialog::currentChangedThroughResort(const QModelIndex &index)
Chris@401 341 {
Chris@1536 342 #ifdef DEBUG_MODEL_DATA_TABLE_DIALOG
Chris@1536 343 SVDEBUG << "ModelDataTableDialog::currentChangedThroughResort: row = " << index.row() << endl;
Chris@1536 344 #endif
Chris@401 345 makeCurrent(index.row());
Chris@401 346 }
Chris@401 347
Chris@428 348 void
Chris@428 349 ModelDataTableDialog::modelRemoved()
Chris@428 350 {
Chris@428 351 close();
Chris@428 352 }
Chris@401 353
Chris@401 354