annotate widgets/TransformFinder.cpp @ 432:8b2b497d302c

* Fix race condition in FFTFileCache when reading from the same FFT model from multiple threads (e.g. when applying more than one plugin at once)
author Chris Cannam
date Wed, 15 Oct 2008 12:08:02 +0000
parents 4711b400f976
children 1e0744b2cebe
rev   line source
Chris@416 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@416 2
Chris@416 3 /*
Chris@416 4 Sonic Visualiser
Chris@416 5 An audio file viewer and annotation editor.
Chris@416 6 Centre for Digital Music, Queen Mary, University of London.
Chris@416 7 This file copyright 2008 QMUL.
Chris@416 8
Chris@416 9 This program is free software; you can redistribute it and/or
Chris@416 10 modify it under the terms of the GNU General Public License as
Chris@416 11 published by the Free Software Foundation; either version 2 of the
Chris@416 12 License, or (at your option) any later version. See the file
Chris@416 13 COPYING included with this distribution for more information.
Chris@416 14 */
Chris@416 15
Chris@416 16 #include "TransformFinder.h"
Chris@416 17
Chris@424 18 #include "base/XmlExportable.h"
Chris@416 19 #include "transform/TransformFactory.h"
Chris@424 20 #include "SelectableLabel.h"
Chris@416 21
Chris@421 22 #include <QVBoxLayout>
Chris@416 23 #include <QGridLayout>
Chris@416 24 #include <QLineEdit>
Chris@416 25 #include <QLabel>
Chris@416 26 #include <QDialogButtonBox>
Chris@416 27 #include <QScrollArea>
Chris@421 28 #include <QApplication>
Chris@423 29 #include <QDesktopWidget>
Chris@424 30 #include <QTimer>
Chris@426 31 #include <QAction>
Chris@421 32
Chris@416 33 TransformFinder::TransformFinder(QWidget *parent) :
Chris@417 34 QDialog(parent),
Chris@417 35 m_resultsFrame(0),
Chris@417 36 m_resultsLayout(0)
Chris@416 37 {
Chris@416 38 setWindowTitle(tr("Find a Transform"));
Chris@416 39
Chris@416 40 QGridLayout *mainGrid = new QGridLayout;
Chris@421 41 mainGrid->setVerticalSpacing(0);
Chris@416 42 setLayout(mainGrid);
Chris@416 43
Chris@416 44 mainGrid->addWidget(new QLabel(tr("Find:")), 0, 0);
Chris@416 45
Chris@416 46 QLineEdit *searchField = new QLineEdit;
Chris@416 47 mainGrid->addWidget(searchField, 0, 1);
Chris@416 48 connect(searchField, SIGNAL(textChanged(const QString &)),
Chris@416 49 this, SLOT(searchTextChanged(const QString &)));
Chris@416 50
Chris@416 51 m_resultsScroll = new QScrollArea;
Chris@420 52 // m_resultsScroll->setWidgetResizable(true);
Chris@416 53 mainGrid->addWidget(m_resultsScroll, 1, 0, 1, 2);
Chris@416 54 mainGrid->setRowStretch(1, 10);
Chris@416 55
Chris@416 56 QDialogButtonBox *bb = new QDialogButtonBox(QDialogButtonBox::Ok |
Chris@416 57 QDialogButtonBox::Cancel);
Chris@416 58 mainGrid->addWidget(bb, 2, 0, 1, 2);
Chris@416 59 connect(bb, SIGNAL(accepted()), this, SLOT(accept()));
Chris@416 60 connect(bb, SIGNAL(rejected()), this, SLOT(reject()));
Chris@421 61 if (!m_resultsLayout) {
Chris@421 62 std::cerr << "creating frame & layout" << std::endl;
Chris@421 63 m_resultsFrame = new QWidget;
Chris@421 64 QPalette palette = m_resultsFrame->palette();
Chris@421 65 palette.setColor(QPalette::Window, palette.color(QPalette::Base));
Chris@421 66 m_resultsFrame->setPalette(palette);
Chris@421 67 m_resultsScroll->setPalette(palette);
Chris@421 68 m_resultsLayout = new QVBoxLayout;
Chris@423 69 m_resultsLayout->setSpacing(0);
Chris@423 70 m_resultsLayout->setContentsMargins(0, 0, 0, 0);
Chris@421 71 m_resultsFrame->setLayout(m_resultsLayout);
Chris@421 72 m_resultsScroll->setWidget(m_resultsFrame);
Chris@421 73 m_resultsFrame->show();
Chris@421 74 }
Chris@416 75
Chris@426 76 QAction *up = new QAction(tr("Up"), this);
Chris@426 77 up->setShortcut(tr("Up"));
Chris@426 78 connect(up, SIGNAL(triggered()), this, SLOT(up()));
Chris@426 79 addAction(up);
Chris@426 80
Chris@426 81 QAction *down = new QAction(tr("Down"), this);
Chris@426 82 down->setShortcut(tr("Down"));
Chris@426 83 connect(down, SIGNAL(triggered()), this, SLOT(down()));
Chris@426 84 addAction(down);
Chris@426 85
Chris@423 86 QDesktopWidget *desktop = QApplication::desktop();
Chris@423 87 QRect available = desktop->availableGeometry();
Chris@423 88
Chris@423 89 int width = available.width() / 2;
Chris@423 90 int height = available.height() / 2;
Chris@423 91 if (height < 450) {
Chris@423 92 if (available.height() > 500) height = 450;
Chris@423 93 }
Chris@423 94 if (width < 600) {
Chris@423 95 if (available.width() > 650) width = 600;
Chris@423 96 }
Chris@423 97
Chris@423 98 resize(width, height);
Chris@423 99 raise();
Chris@424 100
Chris@424 101 m_upToDateCount = 0;
Chris@424 102 m_timer = new QTimer(this);
Chris@424 103 connect(m_timer, SIGNAL(timeout()), this, SLOT(timeout()));
Chris@425 104 m_timer->start(30);
Chris@416 105 }
Chris@416 106
Chris@416 107 TransformFinder::~TransformFinder()
Chris@416 108 {
Chris@416 109 }
Chris@416 110
Chris@416 111 void
Chris@416 112 TransformFinder::searchTextChanged(const QString &text)
Chris@416 113 {
Chris@416 114 std::cerr << "text is " << text.toStdString() << std::endl;
Chris@424 115 m_newSearchText = text;
Chris@424 116 }
Chris@416 117
Chris@424 118 void
Chris@424 119 TransformFinder::timeout()
Chris@424 120 {
Chris@424 121 int maxResults = 40;
Chris@416 122
Chris@424 123 if (m_newSearchText != "") {
Chris@416 124
Chris@424 125 QString text = m_newSearchText;
Chris@424 126 m_newSearchText = "";
Chris@424 127
Chris@424 128 QStringList keywords = text.split(' ', QString::SkipEmptyParts);
Chris@424 129 TransformFactory::SearchResults results =
Chris@424 130 TransformFactory::getInstance()->search(keywords);
Chris@424 131
Chris@424 132 std::cerr << results.size() << " result(s)..." << std::endl;
Chris@424 133
Chris@431 134 std::set<TextMatcher::Match> sorted;
Chris@424 135 sorted.clear();
Chris@424 136 for (TransformFactory::SearchResults::const_iterator j = results.begin();
Chris@424 137 j != results.end(); ++j) {
Chris@424 138 sorted.insert(j->second);
Chris@424 139 }
Chris@424 140
Chris@424 141 m_sortedResults.clear();
Chris@431 142 for (std::set<TextMatcher::Match>::const_iterator j = sorted.end();
Chris@424 143 j != sorted.begin(); ) {
Chris@424 144 --j;
Chris@424 145 m_sortedResults.push_back(*j);
Chris@424 146 if (m_sortedResults.size() == maxResults) break;
Chris@424 147 }
Chris@424 148
Chris@424 149 if (m_sortedResults.empty()) m_selectedTransform = "";
Chris@431 150 else m_selectedTransform = m_sortedResults.begin()->key;
Chris@424 151
Chris@424 152 m_upToDateCount = 0;
Chris@424 153
Chris@424 154 for (int j = m_labels.size(); j > m_sortedResults.size(); ) {
Chris@424 155 m_labels[--j]->hide();
Chris@424 156 }
Chris@424 157
Chris@424 158 return;
Chris@416 159 }
Chris@416 160
Chris@425 161 if (m_upToDateCount >= m_sortedResults.size()) return;
Chris@425 162
Chris@425 163 while (m_upToDateCount < m_sortedResults.size()) {
Chris@417 164
Chris@424 165 int i = m_upToDateCount;
Chris@416 166
Chris@431 167 // std::cerr << "sorted size = " << m_sortedResults.size() << std::endl;
Chris@417 168
Chris@431 169 TransformDescription desc;
Chris@431 170 TransformId tid = m_sortedResults[i].key;
Chris@431 171 TransformFactory *factory = TransformFactory::getInstance();
Chris@431 172 TransformFactory::TransformInstallStatus status =
Chris@431 173 factory->getTransformInstallStatus(tid);
Chris@431 174 QString suffix;
Chris@431 175
Chris@431 176 if (status == TransformFactory::TransformInstalled) {
Chris@431 177 desc = factory->getTransformDescription(tid);
Chris@431 178 } else {
Chris@431 179 desc = factory->getUninstalledTransformDescription(tid);
Chris@431 180 suffix = tr("<i> (not installed)</i>");
Chris@431 181 }
Chris@419 182
Chris@419 183 QString labelText;
Chris@431 184 labelText += tr("%1%2<br><small>")
Chris@431 185 .arg(XmlExportable::encodeEntities(desc.name))
Chris@431 186 .arg(suffix);
Chris@424 187
Chris@416 188 labelText += "...";
Chris@431 189 for (TextMatcher::Match::FragmentMap::const_iterator k =
Chris@424 190 m_sortedResults[i].fragments.begin();
Chris@424 191 k != m_sortedResults[i].fragments.end(); ++k) {
Chris@416 192 labelText += k->second;
Chris@416 193 labelText += "... ";
Chris@416 194 }
Chris@416 195 labelText += tr("</small>");
Chris@417 196
Chris@419 197 QString selectedText;
Chris@431 198 selectedText += tr("<b>%1</b>%2<br>")
Chris@431 199 .arg(XmlExportable::encodeEntities
Chris@431 200 (desc.name == "" ? desc.identifier : desc.name))
Chris@431 201 .arg(suffix);
Chris@431 202
Chris@431 203 if (desc.longDescription != "") {
Chris@431 204 selectedText += tr("<small>%1</small>")
Chris@431 205 .arg(XmlExportable::encodeEntities(desc.longDescription));
Chris@431 206 } else if (desc.description != "") {
Chris@431 207 selectedText += tr("<small>%1</small>")
Chris@431 208 .arg(XmlExportable::encodeEntities(desc.description));
Chris@431 209 }
Chris@419 210
Chris@426 211 selectedText += tr("<br><small>");
Chris@431 212 if (desc.type != "") {
Chris@431 213 selectedText += tr("&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&mdash; Plugin type: %1<br>")
Chris@431 214 .arg(XmlExportable::encodeEntities(desc.type));
Chris@431 215 }
Chris@431 216 if (desc.category != "") {
Chris@431 217 selectedText += tr("&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&mdash; Category: %1<br>")
Chris@431 218 .arg(XmlExportable::encodeEntities(desc.category));
Chris@431 219 }
Chris@426 220 selectedText += tr("&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&mdash; System identifier: %1")
Chris@424 221 .arg(XmlExportable::encodeEntities(desc.identifier));
Chris@426 222 selectedText += tr("</small>");
Chris@419 223
Chris@417 224 if (i >= m_labels.size()) {
Chris@419 225 SelectableLabel *label = new SelectableLabel(m_resultsFrame);
Chris@421 226 m_resultsLayout->addWidget(label);
Chris@420 227 connect(label, SIGNAL(selectionChanged()), this,
Chris@420 228 SLOT(selectedLabelChanged()));
Chris@424 229 connect(label, SIGNAL(doubleClicked()), this,
Chris@424 230 SLOT(accept()));
Chris@421 231 QPalette palette = label->palette();
Chris@421 232 label->setPalette(palette);
Chris@417 233 m_labels.push_back(label);
Chris@417 234 }
Chris@421 235
Chris@420 236 m_labels[i]->setObjectName(desc.identifier);
Chris@423 237 m_labels[i]->setFixedWidth(this->width() - 40);
Chris@419 238 m_labels[i]->setUnselectedText(labelText);
Chris@425 239
Chris@425 240 // std::cerr << "selected text: " << selectedText.toStdString() << std::endl;
Chris@419 241 m_labels[i]->setSelectedText(selectedText);
Chris@423 242
Chris@424 243 m_labels[i]->setSelected(m_selectedTransform == desc.identifier);
Chris@425 244
Chris@425 245 if (!m_labels[i]->isVisible()) m_labels[i]->show();
Chris@417 246
Chris@424 247 ++m_upToDateCount;
Chris@424 248
Chris@425 249 if (i == 0) break;
Chris@416 250 }
Chris@425 251
Chris@425 252 m_resultsFrame->resize(m_resultsFrame->sizeHint());
Chris@416 253 }
Chris@416 254
Chris@420 255 void
Chris@420 256 TransformFinder::selectedLabelChanged()
Chris@420 257 {
Chris@420 258 QObject *s = sender();
Chris@420 259 m_selectedTransform = "";
Chris@420 260 for (int i = 0; i < m_labels.size(); ++i) {
Chris@420 261 if (!m_labels[i]->isVisible()) continue;
Chris@420 262 if (m_labels[i] == s) {
Chris@420 263 if (m_labels[i]->isSelected()) {
Chris@420 264 m_selectedTransform = m_labels[i]->objectName();
Chris@420 265 }
Chris@420 266 } else {
Chris@420 267 if (m_labels[i]->isSelected()) {
Chris@420 268 m_labels[i]->setSelected(false);
Chris@420 269 }
Chris@420 270 }
Chris@420 271 }
Chris@420 272 std::cerr << "selectedLabelChanged: selected transform is now \""
Chris@420 273 << m_selectedTransform.toStdString() << "\"" << std::endl;
Chris@420 274 }
Chris@420 275
Chris@416 276 TransformId
Chris@416 277 TransformFinder::getTransform() const
Chris@416 278 {
Chris@424 279 return m_selectedTransform;
Chris@416 280 }
Chris@416 281
Chris@426 282 void
Chris@426 283 TransformFinder::up()
Chris@426 284 {
Chris@426 285 for (int i = 0; i < m_labels.size(); ++i) {
Chris@426 286 if (!m_labels[i]->isVisible()) continue;
Chris@426 287 if (m_labels[i]->objectName() == m_selectedTransform) {
Chris@426 288 if (i > 0) {
Chris@426 289 m_labels[i]->setSelected(false);
Chris@426 290 m_labels[i-1]->setSelected(true);
Chris@426 291 m_selectedTransform = m_labels[i-1]->objectName();
Chris@426 292 }
Chris@426 293 return;
Chris@426 294 }
Chris@426 295 }
Chris@426 296 }
Chris@426 297
Chris@426 298 void
Chris@426 299 TransformFinder::down()
Chris@426 300 {
Chris@426 301 for (int i = 0; i < m_labels.size(); ++i) {
Chris@426 302 if (!m_labels[i]->isVisible()) continue;
Chris@426 303 if (m_labels[i]->objectName() == m_selectedTransform) {
Chris@426 304 if (i+1 < m_labels.size() &&
Chris@426 305 m_labels[i+1]->isVisible()) {
Chris@426 306 m_labels[i]->setSelected(false);
Chris@426 307 m_labels[i+1]->setSelected(true);
Chris@426 308 m_selectedTransform = m_labels[i+1]->objectName();
Chris@426 309 }
Chris@426 310 return;
Chris@426 311 }
Chris@426 312 }
Chris@426 313 }
Chris@426 314