annotate widgets/ModelDataTableDialog.cpp @ 1605:ae2d5f8ff005

When asked to render the whole view width, we need to wait for the layers to be ready before we can determine what the width is
author Chris Cannam
date Thu, 30 Apr 2020 14:47:13 +0100
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