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