annotate widgets/TransformFinder.cpp @ 454:e2a40fdadd8c

Various fixes: * Fix handling of HTTP redirects (avoiding crashes... I hope) * Fix failure to delete FFT models when a feature extraction model transformer was abandoned (also a cause of crashes in the past) * Fix deadlock when said transform was abandoned before its source model was ready because the session was being cleared (and so the source model would never be ready)
author Chris Cannam
date Fri, 28 Nov 2008 13:36:13 +0000
parents 7bec0807d7ba
children 1fe7951a61e8
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@450 51 // m_infoLabel = new QLabel(tr("Type in this box to search descriptions of available and known transforms"));
Chris@450 52 m_infoLabel = new QLabel;
Chris@448 53 mainGrid->addWidget(m_infoLabel, 1, 1);
Chris@448 54
Chris@416 55 m_resultsScroll = new QScrollArea;
Chris@448 56 mainGrid->addWidget(m_resultsScroll, 2, 0, 1, 2);
Chris@448 57 mainGrid->setRowStretch(2, 10);
Chris@416 58
Chris@416 59 QDialogButtonBox *bb = new QDialogButtonBox(QDialogButtonBox::Ok |
Chris@416 60 QDialogButtonBox::Cancel);
Chris@448 61 mainGrid->addWidget(bb, 3, 0, 1, 2);
Chris@416 62 connect(bb, SIGNAL(accepted()), this, SLOT(accept()));
Chris@416 63 connect(bb, SIGNAL(rejected()), this, SLOT(reject()));
Chris@448 64
Chris@448 65 m_resultsFrame = new QWidget;
Chris@448 66 QPalette palette = m_resultsFrame->palette();
Chris@448 67 palette.setColor(QPalette::Window, palette.color(QPalette::Base));
Chris@448 68 m_resultsFrame->setPalette(palette);
Chris@448 69 m_resultsScroll->setPalette(palette);
Chris@448 70 m_resultsLayout = new QVBoxLayout;
Chris@448 71 m_resultsLayout->setSpacing(0);
Chris@448 72 m_resultsLayout->setContentsMargins(0, 0, 0, 0);
Chris@448 73 m_resultsFrame->setLayout(m_resultsLayout);
Chris@448 74 m_resultsScroll->setWidget(m_resultsFrame);
Chris@448 75 m_resultsFrame->show();
Chris@448 76
Chris@448 77 m_noResultsLabel = new QLabel(tr("<br>&nbsp;&nbsp;No results found"));
Chris@448 78 m_resultsLayout->addWidget(m_noResultsLabel);
Chris@448 79 m_noResultsLabel->hide();
Chris@448 80
Chris@448 81 m_beforeSearchLabel = new QLabel;
Chris@448 82 m_resultsLayout->addWidget(m_beforeSearchLabel);
Chris@448 83 m_beforeSearchLabel->hide();
Chris@416 84
Chris@426 85 QAction *up = new QAction(tr("Up"), this);
Chris@426 86 up->setShortcut(tr("Up"));
Chris@426 87 connect(up, SIGNAL(triggered()), this, SLOT(up()));
Chris@426 88 addAction(up);
Chris@426 89
Chris@426 90 QAction *down = new QAction(tr("Down"), this);
Chris@426 91 down->setShortcut(tr("Down"));
Chris@426 92 connect(down, SIGNAL(triggered()), this, SLOT(down()));
Chris@426 93 addAction(down);
Chris@426 94
Chris@423 95 QDesktopWidget *desktop = QApplication::desktop();
Chris@423 96 QRect available = desktop->availableGeometry();
Chris@423 97
Chris@423 98 int width = available.width() / 2;
Chris@423 99 int height = available.height() / 2;
Chris@423 100 if (height < 450) {
Chris@423 101 if (available.height() > 500) height = 450;
Chris@423 102 }
Chris@423 103 if (width < 600) {
Chris@423 104 if (available.width() > 650) width = 600;
Chris@423 105 }
Chris@423 106
Chris@423 107 resize(width, height);
Chris@423 108 raise();
Chris@424 109
Chris@450 110 setupBeforeSearchLabel();
Chris@450 111
Chris@424 112 m_upToDateCount = 0;
Chris@424 113 m_timer = new QTimer(this);
Chris@424 114 connect(m_timer, SIGNAL(timeout()), this, SLOT(timeout()));
Chris@425 115 m_timer->start(30);
Chris@416 116 }
Chris@416 117
Chris@416 118 TransformFinder::~TransformFinder()
Chris@416 119 {
Chris@416 120 }
Chris@416 121
Chris@416 122 void
Chris@450 123 TransformFinder::setupBeforeSearchLabel()
Chris@450 124 {
Chris@450 125 bool haveInstalled =
Chris@450 126 TransformFactory::getInstance()->haveInstalledTransforms();
Chris@450 127 bool haveUninstalled =
Chris@450 128 TransformFactory::getInstance()->haveUninstalledTransforms();
Chris@450 129
Chris@450 130 m_beforeSearchLabel->setWordWrap(true);
Chris@450 131 m_beforeSearchLabel->setOpenExternalLinks(true);
Chris@450 132 m_beforeSearchLabel->setTextInteractionFlags(Qt::LinksAccessibleByMouse);
Chris@450 133 m_beforeSearchLabel->setMargin(12);
Chris@450 134 m_beforeSearchLabel->setFixedWidth(this->width() - 40);
Chris@450 135
Chris@450 136 QString base =
Chris@450 137 tr("<p>Type some text into the search box to search the descriptions of:<ul><li>All currently installed <a href=\"http://www.vamp-plugins.org/\">Vamp</a> audio feature extraction plugins</li><li>All currently installed <a href=\"http://www.ladspa.org/\">LADSPA</a> audio effects plugins</li><li>Vamp plugins that are not currently installed but that have descriptions published via the semantic web</li></ul>");
Chris@450 138
Chris@450 139 QString nopull =
Chris@450 140 tr("<b>Unable to retrieve published descriptions from network!</b>");
Chris@450 141
Chris@450 142 QString noinst =
Chris@450 143 tr("<b>No plugins are currently installed!</b>");
Chris@450 144
Chris@450 145 if (haveInstalled) {
Chris@450 146 if (haveUninstalled) {
Chris@450 147 m_beforeSearchLabel->setText(base);
Chris@450 148 } else {
Chris@450 149 m_beforeSearchLabel->setText
Chris@450 150 (base +
Chris@451 151 tr("<p>%1<br>Perhaps the network connection is down, services are responding too slowly, or a processing problem has occurred.<br>Only the descriptions of installed plugins will be searched.").arg(nopull));
Chris@450 152 }
Chris@450 153 } else {
Chris@450 154 if (haveUninstalled) {
Chris@450 155 m_beforeSearchLabel->setText
Chris@450 156 (base +
Chris@450 157 tr("<p>%1<br>Only the published descriptions of Vamp feature extraction plugins will be searched.").arg(noinst));
Chris@450 158 } else {
Chris@450 159 m_beforeSearchLabel->setText
Chris@450 160 (base +
Chris@450 161 tr("<p>%1<br>%2<br>Perhaps the network connection is down, or services are responding too slowly.<br>No search results will be available.").arg(noinst).arg(nopull));
Chris@450 162 }
Chris@450 163 }
Chris@450 164
Chris@450 165 m_beforeSearchLabel->show();
Chris@450 166 m_resultsFrame->resize(m_resultsFrame->sizeHint());
Chris@450 167 }
Chris@450 168
Chris@450 169 void
Chris@416 170 TransformFinder::searchTextChanged(const QString &text)
Chris@416 171 {
Chris@448 172 // std::cerr << "text is " << text.toStdString() << std::endl;
Chris@424 173 m_newSearchText = text;
Chris@424 174 }
Chris@416 175
Chris@424 176 void
Chris@424 177 TransformFinder::timeout()
Chris@424 178 {
Chris@448 179 int maxResults = 60;
Chris@416 180
Chris@424 181 if (m_newSearchText != "") {
Chris@416 182
Chris@424 183 QString text = m_newSearchText;
Chris@424 184 m_newSearchText = "";
Chris@424 185
Chris@424 186 QStringList keywords = text.split(' ', QString::SkipEmptyParts);
Chris@424 187 TransformFactory::SearchResults results =
Chris@424 188 TransformFactory::getInstance()->search(keywords);
Chris@424 189
Chris@448 190 // std::cerr << results.size() << " result(s)..." << std::endl;
Chris@424 191
Chris@431 192 std::set<TextMatcher::Match> sorted;
Chris@424 193 sorted.clear();
Chris@424 194 for (TransformFactory::SearchResults::const_iterator j = results.begin();
Chris@424 195 j != results.end(); ++j) {
Chris@424 196 sorted.insert(j->second);
Chris@424 197 }
Chris@448 198
Chris@424 199 m_sortedResults.clear();
Chris@431 200 for (std::set<TextMatcher::Match>::const_iterator j = sorted.end();
Chris@424 201 j != sorted.begin(); ) {
Chris@424 202 --j;
Chris@424 203 m_sortedResults.push_back(*j);
Chris@424 204 if (m_sortedResults.size() == maxResults) break;
Chris@424 205 }
Chris@424 206
Chris@424 207 if (m_sortedResults.empty()) m_selectedTransform = "";
Chris@431 208 else m_selectedTransform = m_sortedResults.begin()->key;
Chris@424 209
Chris@424 210 m_upToDateCount = 0;
Chris@424 211
Chris@424 212 for (int j = m_labels.size(); j > m_sortedResults.size(); ) {
Chris@424 213 m_labels[--j]->hide();
Chris@424 214 }
Chris@424 215
Chris@450 216 m_beforeSearchLabel->hide();
Chris@450 217
Chris@448 218 if (m_sortedResults.empty()) {
Chris@448 219 m_noResultsLabel->show();
Chris@448 220 m_resultsFrame->resize(m_resultsFrame->sizeHint());
Chris@448 221 } else {
Chris@448 222 m_noResultsLabel->hide();
Chris@448 223 }
Chris@448 224
Chris@448 225 if (m_sortedResults.size() < sorted.size()) {
Chris@448 226 m_infoLabel->setText
Chris@448 227 (tr("Found %n description(s) containing <b>%1</b>, showing the first %2 only",
Chris@448 228 0, sorted.size()).arg(text).arg(m_sortedResults.size()));
Chris@448 229 } else {
Chris@448 230 m_infoLabel->setText
Chris@448 231 (tr("Found %n description(s) containing <b>%1</b>",
Chris@448 232 0, sorted.size()).arg(text));
Chris@448 233 }
Chris@448 234
Chris@424 235 return;
Chris@416 236 }
Chris@416 237
Chris@425 238 if (m_upToDateCount >= m_sortedResults.size()) return;
Chris@425 239
Chris@425 240 while (m_upToDateCount < m_sortedResults.size()) {
Chris@417 241
Chris@424 242 int i = m_upToDateCount;
Chris@416 243
Chris@431 244 // std::cerr << "sorted size = " << m_sortedResults.size() << std::endl;
Chris@417 245
Chris@431 246 TransformDescription desc;
Chris@431 247 TransformId tid = m_sortedResults[i].key;
Chris@431 248 TransformFactory *factory = TransformFactory::getInstance();
Chris@431 249 TransformFactory::TransformInstallStatus status =
Chris@431 250 factory->getTransformInstallStatus(tid);
Chris@431 251 QString suffix;
Chris@431 252
Chris@431 253 if (status == TransformFactory::TransformInstalled) {
Chris@431 254 desc = factory->getTransformDescription(tid);
Chris@431 255 } else {
Chris@431 256 desc = factory->getUninstalledTransformDescription(tid);
Chris@431 257 suffix = tr("<i> (not installed)</i>");
Chris@431 258 }
Chris@419 259
Chris@419 260 QString labelText;
Chris@431 261 labelText += tr("%1%2<br><small>")
Chris@431 262 .arg(XmlExportable::encodeEntities(desc.name))
Chris@431 263 .arg(suffix);
Chris@424 264
Chris@416 265 labelText += "...";
Chris@431 266 for (TextMatcher::Match::FragmentMap::const_iterator k =
Chris@424 267 m_sortedResults[i].fragments.begin();
Chris@424 268 k != m_sortedResults[i].fragments.end(); ++k) {
Chris@416 269 labelText += k->second;
Chris@416 270 labelText += "... ";
Chris@416 271 }
Chris@416 272 labelText += tr("</small>");
Chris@417 273
Chris@419 274 QString selectedText;
Chris@431 275 selectedText += tr("<b>%1</b>%2<br>")
Chris@431 276 .arg(XmlExportable::encodeEntities
Chris@431 277 (desc.name == "" ? desc.identifier : desc.name))
Chris@431 278 .arg(suffix);
Chris@431 279
Chris@431 280 if (desc.longDescription != "") {
Chris@431 281 selectedText += tr("<small>%1</small>")
Chris@431 282 .arg(XmlExportable::encodeEntities(desc.longDescription));
Chris@431 283 } else if (desc.description != "") {
Chris@431 284 selectedText += tr("<small>%1</small>")
Chris@431 285 .arg(XmlExportable::encodeEntities(desc.description));
Chris@431 286 }
Chris@419 287
Chris@436 288 selectedText += tr("<small>");
Chris@453 289 if (desc.type != TransformDescription::UnknownType) {
Chris@436 290 selectedText += tr("<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&mdash; Plugin type: %1")
Chris@453 291 .arg(XmlExportable::encodeEntities(factory->getTransformTypeName(desc.type)));
Chris@431 292 }
Chris@431 293 if (desc.category != "") {
Chris@436 294 selectedText += tr("<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&mdash; Category: %1")
Chris@431 295 .arg(XmlExportable::encodeEntities(desc.category));
Chris@431 296 }
Chris@436 297 selectedText += tr("<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&mdash; System identifier: %1")
Chris@424 298 .arg(XmlExportable::encodeEntities(desc.identifier));
Chris@436 299 if (desc.infoUrl != "") {
Chris@436 300 selectedText += tr("<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&mdash; More information: <a href=\"%1\">%1</a>")
Chris@436 301 .arg(desc.infoUrl);
Chris@436 302 }
Chris@426 303 selectedText += tr("</small>");
Chris@419 304
Chris@417 305 if (i >= m_labels.size()) {
Chris@419 306 SelectableLabel *label = new SelectableLabel(m_resultsFrame);
Chris@421 307 m_resultsLayout->addWidget(label);
Chris@420 308 connect(label, SIGNAL(selectionChanged()), this,
Chris@420 309 SLOT(selectedLabelChanged()));
Chris@424 310 connect(label, SIGNAL(doubleClicked()), this,
Chris@448 311 SLOT(labelDoubleClicked()));
Chris@421 312 QPalette palette = label->palette();
Chris@421 313 label->setPalette(palette);
Chris@417 314 m_labels.push_back(label);
Chris@417 315 }
Chris@421 316
Chris@420 317 m_labels[i]->setObjectName(desc.identifier);
Chris@423 318 m_labels[i]->setFixedWidth(this->width() - 40);
Chris@419 319 m_labels[i]->setUnselectedText(labelText);
Chris@425 320
Chris@425 321 // std::cerr << "selected text: " << selectedText.toStdString() << std::endl;
Chris@419 322 m_labels[i]->setSelectedText(selectedText);
Chris@423 323
Chris@424 324 m_labels[i]->setSelected(m_selectedTransform == desc.identifier);
Chris@425 325
Chris@425 326 if (!m_labels[i]->isVisible()) m_labels[i]->show();
Chris@417 327
Chris@424 328 ++m_upToDateCount;
Chris@424 329
Chris@425 330 if (i == 0) break;
Chris@416 331 }
Chris@425 332
Chris@425 333 m_resultsFrame->resize(m_resultsFrame->sizeHint());
Chris@416 334 }
Chris@416 335
Chris@420 336 void
Chris@420 337 TransformFinder::selectedLabelChanged()
Chris@420 338 {
Chris@420 339 QObject *s = sender();
Chris@420 340 m_selectedTransform = "";
Chris@420 341 for (int i = 0; i < m_labels.size(); ++i) {
Chris@420 342 if (!m_labels[i]->isVisible()) continue;
Chris@420 343 if (m_labels[i] == s) {
Chris@420 344 if (m_labels[i]->isSelected()) {
Chris@420 345 m_selectedTransform = m_labels[i]->objectName();
Chris@420 346 }
Chris@420 347 } else {
Chris@420 348 if (m_labels[i]->isSelected()) {
Chris@420 349 m_labels[i]->setSelected(false);
Chris@420 350 }
Chris@420 351 }
Chris@420 352 }
Chris@420 353 std::cerr << "selectedLabelChanged: selected transform is now \""
Chris@420 354 << m_selectedTransform.toStdString() << "\"" << std::endl;
Chris@420 355 }
Chris@420 356
Chris@448 357 void
Chris@448 358 TransformFinder::labelDoubleClicked()
Chris@448 359 {
Chris@448 360 // The first click should have selected the label already
Chris@448 361 if (TransformFactory::getInstance()->getTransformInstallStatus
Chris@448 362 (m_selectedTransform) ==
Chris@448 363 TransformFactory::TransformInstalled) {
Chris@448 364 accept();
Chris@448 365 }
Chris@448 366 }
Chris@448 367
Chris@416 368 TransformId
Chris@416 369 TransformFinder::getTransform() const
Chris@416 370 {
Chris@424 371 return m_selectedTransform;
Chris@416 372 }
Chris@416 373
Chris@426 374 void
Chris@426 375 TransformFinder::up()
Chris@426 376 {
Chris@426 377 for (int i = 0; i < m_labels.size(); ++i) {
Chris@426 378 if (!m_labels[i]->isVisible()) continue;
Chris@426 379 if (m_labels[i]->objectName() == m_selectedTransform) {
Chris@426 380 if (i > 0) {
Chris@426 381 m_labels[i]->setSelected(false);
Chris@426 382 m_labels[i-1]->setSelected(true);
Chris@426 383 m_selectedTransform = m_labels[i-1]->objectName();
Chris@426 384 }
Chris@426 385 return;
Chris@426 386 }
Chris@426 387 }
Chris@426 388 }
Chris@426 389
Chris@426 390 void
Chris@426 391 TransformFinder::down()
Chris@426 392 {
Chris@426 393 for (int i = 0; i < m_labels.size(); ++i) {
Chris@426 394 if (!m_labels[i]->isVisible()) continue;
Chris@426 395 if (m_labels[i]->objectName() == m_selectedTransform) {
Chris@426 396 if (i+1 < m_labels.size() &&
Chris@426 397 m_labels[i+1]->isVisible()) {
Chris@426 398 m_labels[i]->setSelected(false);
Chris@426 399 m_labels[i+1]->setSelected(true);
Chris@426 400 m_selectedTransform = m_labels[i+1]->objectName();
Chris@426 401 }
Chris@426 402 return;
Chris@426 403 }
Chris@426 404 }
Chris@426 405 }
Chris@426 406