svgui
1.9
|
00001 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ 00002 00003 /* 00004 Sonic Visualiser 00005 An audio file viewer and annotation editor. 00006 Centre for Digital Music, Queen Mary, University of London. 00007 This file copyright 2008 QMUL. 00008 00009 This program is free software; you can redistribute it and/or 00010 modify it under the terms of the GNU General Public License as 00011 published by the Free Software Foundation; either version 2 of the 00012 License, or (at your option) any later version. See the file 00013 COPYING included with this distribution for more information. 00014 */ 00015 00016 #include "TransformFinder.h" 00017 00018 #include "base/XmlExportable.h" 00019 #include "transform/TransformFactory.h" 00020 #include "SelectableLabel.h" 00021 00022 #include <QVBoxLayout> 00023 #include <QGridLayout> 00024 #include <QLineEdit> 00025 #include <QLabel> 00026 #include <QDialogButtonBox> 00027 #include <QScrollArea> 00028 #include <QApplication> 00029 #include <QDesktopWidget> 00030 #include <QTimer> 00031 #include <QAction> 00032 00033 TransformFinder::TransformFinder(QWidget *parent) : 00034 QDialog(parent), 00035 m_resultsFrame(0), 00036 m_resultsLayout(0) 00037 { 00038 setWindowTitle(tr("Find a Transform")); 00039 00040 QGridLayout *mainGrid = new QGridLayout; 00041 mainGrid->setVerticalSpacing(0); 00042 setLayout(mainGrid); 00043 00044 mainGrid->addWidget(new QLabel(tr("Find:")), 0, 0); 00045 00046 QLineEdit *searchField = new QLineEdit; 00047 mainGrid->addWidget(searchField, 0, 1); 00048 connect(searchField, SIGNAL(textChanged(const QString &)), 00049 this, SLOT(searchTextChanged(const QString &))); 00050 00051 // m_infoLabel = new QLabel(tr("Type in this box to search descriptions of available and known transforms")); 00052 m_infoLabel = new QLabel; 00053 mainGrid->addWidget(m_infoLabel, 1, 1); 00054 00055 m_resultsScroll = new QScrollArea; 00056 mainGrid->addWidget(m_resultsScroll, 2, 0, 1, 2); 00057 mainGrid->setRowStretch(2, 10); 00058 00059 QDialogButtonBox *bb = new QDialogButtonBox(QDialogButtonBox::Ok | 00060 QDialogButtonBox::Cancel); 00061 mainGrid->addWidget(bb, 3, 0, 1, 2); 00062 connect(bb, SIGNAL(accepted()), this, SLOT(accept())); 00063 connect(bb, SIGNAL(rejected()), this, SLOT(reject())); 00064 00065 m_resultsFrame = new QWidget; 00066 QPalette palette = m_resultsFrame->palette(); 00067 palette.setColor(QPalette::Window, palette.color(QPalette::Base)); 00068 m_resultsFrame->setPalette(palette); 00069 m_resultsScroll->setPalette(palette); 00070 m_resultsLayout = new QVBoxLayout; 00071 m_resultsLayout->setSpacing(0); 00072 m_resultsLayout->setContentsMargins(0, 0, 0, 0); 00073 m_resultsFrame->setLayout(m_resultsLayout); 00074 m_resultsScroll->setWidget(m_resultsFrame); 00075 m_resultsFrame->show(); 00076 00077 m_noResultsLabel = new QLabel(tr("<br> No results found")); 00078 m_resultsLayout->addWidget(m_noResultsLabel); 00079 m_noResultsLabel->hide(); 00080 00081 m_beforeSearchLabel = new QLabel; 00082 m_resultsLayout->addWidget(m_beforeSearchLabel); 00083 m_beforeSearchLabel->hide(); 00084 00085 QAction *up = new QAction(tr("Up"), this); 00086 up->setShortcut(tr("Up")); 00087 connect(up, SIGNAL(triggered()), this, SLOT(up())); 00088 addAction(up); 00089 00090 QAction *down = new QAction(tr("Down"), this); 00091 down->setShortcut(tr("Down")); 00092 connect(down, SIGNAL(triggered()), this, SLOT(down())); 00093 addAction(down); 00094 00095 QDesktopWidget *desktop = QApplication::desktop(); 00096 QRect available = desktop->availableGeometry(); 00097 00098 int width = available.width() / 2; 00099 int height = available.height() / 2; 00100 if (height < 450) { 00101 if (available.height() > 500) height = 450; 00102 } 00103 if (width < 600) { 00104 if (available.width() > 650) width = 600; 00105 } 00106 00107 resize(width, height); 00108 raise(); 00109 00110 setupBeforeSearchLabel(); 00111 00112 m_upToDateCount = 0; 00113 m_timer = new QTimer(this); 00114 connect(m_timer, SIGNAL(timeout()), this, SLOT(timeout())); 00115 m_timer->start(30); 00116 } 00117 00118 TransformFinder::~TransformFinder() 00119 { 00120 } 00121 00122 void 00123 TransformFinder::setupBeforeSearchLabel() 00124 { 00125 bool haveInstalled = 00126 TransformFactory::getInstance()->haveInstalledTransforms(); 00127 bool haveUninstalled = 00128 TransformFactory::getInstance()->haveUninstalledTransforms(); 00129 00130 m_beforeSearchLabel->setWordWrap(true); 00131 m_beforeSearchLabel->setOpenExternalLinks(true); 00132 m_beforeSearchLabel->setTextInteractionFlags(Qt::LinksAccessibleByMouse); 00133 m_beforeSearchLabel->setMargin(12); 00134 m_beforeSearchLabel->setFixedWidth(this->width() - 40); 00135 00136 QString base = 00137 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>"); 00138 00139 QString nopull = 00140 tr("<b>Unable to retrieve published descriptions from network!</b>"); 00141 00142 QString noinst = 00143 tr("<b>No plugins are currently installed!</b>"); 00144 00145 if (haveInstalled) { 00146 if (haveUninstalled) { 00147 m_beforeSearchLabel->setText(base); 00148 } else { 00149 m_beforeSearchLabel->setText 00150 (base + 00151 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)); 00152 } 00153 } else { 00154 if (haveUninstalled) { 00155 m_beforeSearchLabel->setText 00156 (base + 00157 tr("<p>%1<br>Only the published descriptions of Vamp feature extraction plugins will be searched.").arg(noinst)); 00158 } else { 00159 m_beforeSearchLabel->setText 00160 (base + 00161 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)); 00162 } 00163 } 00164 00165 m_beforeSearchLabel->show(); 00166 m_resultsFrame->resize(m_resultsFrame->sizeHint()); 00167 } 00168 00169 void 00170 TransformFinder::searchTextChanged(const QString &text) 00171 { 00172 // cerr << "text is " << text << endl; 00173 m_newSearchText = text; 00174 } 00175 00176 void 00177 TransformFinder::timeout() 00178 { 00179 int maxResults = 60; 00180 00181 if (m_newSearchText != "") { 00182 00183 QString text = m_newSearchText; 00184 m_newSearchText = ""; 00185 00186 QStringList keywords = text.split(' ', QString::SkipEmptyParts); 00187 TransformFactory::SearchResults results = 00188 TransformFactory::getInstance()->search(keywords); 00189 00190 // cerr << results.size() << " result(s)..." << endl; 00191 00192 std::set<TextMatcher::Match> sorted; 00193 sorted.clear(); 00194 for (TransformFactory::SearchResults::const_iterator j = results.begin(); 00195 j != results.end(); ++j) { 00196 sorted.insert(j->second); 00197 } 00198 00199 m_sortedResults.clear(); 00200 for (std::set<TextMatcher::Match>::const_iterator j = sorted.end(); 00201 j != sorted.begin(); ) { 00202 --j; 00203 m_sortedResults.push_back(*j); 00204 if ((int)m_sortedResults.size() == maxResults) break; 00205 } 00206 00207 if (m_sortedResults.empty()) m_selectedTransform = ""; 00208 else m_selectedTransform = m_sortedResults.begin()->key; 00209 00210 m_upToDateCount = 0; 00211 00212 for (int j = (int)m_labels.size(); j > (int)m_sortedResults.size(); ) { 00213 m_labels[--j]->hide(); 00214 } 00215 00216 m_beforeSearchLabel->hide(); 00217 00218 if (m_sortedResults.empty()) { 00219 m_noResultsLabel->show(); 00220 m_resultsFrame->resize(m_resultsFrame->sizeHint()); 00221 } else { 00222 m_noResultsLabel->hide(); 00223 } 00224 00225 if (m_sortedResults.size() < sorted.size()) { 00226 m_infoLabel->setText 00227 (tr("Found %n description(s) containing <b>%1</b>, showing the first %2 only", 00228 0, sorted.size()).arg(text).arg(m_sortedResults.size())); 00229 } else { 00230 m_infoLabel->setText 00231 (tr("Found %n description(s) containing <b>%1</b>", 00232 0, sorted.size()).arg(text)); 00233 } 00234 00235 return; 00236 } 00237 00238 if (m_upToDateCount >= (int)m_sortedResults.size()) return; 00239 00240 while (m_upToDateCount < (int)m_sortedResults.size()) { 00241 00242 int i = m_upToDateCount; 00243 00244 // cerr << "sorted size = " << m_sortedResults.size() << endl; 00245 00246 TransformDescription desc; 00247 TransformId tid = m_sortedResults[i].key; 00248 TransformFactory *factory = TransformFactory::getInstance(); 00249 TransformFactory::TransformInstallStatus status = 00250 factory->getTransformInstallStatus(tid); 00251 QString suffix; 00252 00253 if (status == TransformFactory::TransformInstalled) { 00254 desc = factory->getTransformDescription(tid); 00255 } else { 00256 desc = factory->getUninstalledTransformDescription(tid); 00257 suffix = tr("<i> (not installed)</i>"); 00258 } 00259 00260 QString labelText; 00261 labelText += tr("%1%2<br><small>") 00262 .arg(XmlExportable::encodeEntities(desc.name)) 00263 .arg(suffix); 00264 00265 labelText += "..."; 00266 for (TextMatcher::Match::FragmentMap::const_iterator k = 00267 m_sortedResults[i].fragments.begin(); 00268 k != m_sortedResults[i].fragments.end(); ++k) { 00269 labelText += k->second; 00270 labelText += "... "; 00271 } 00272 labelText += tr("</small>"); 00273 00274 QString selectedText; 00275 selectedText += tr("<b>%1</b>%2<br>") 00276 .arg(XmlExportable::encodeEntities 00277 (desc.name == "" ? desc.identifier : desc.name)) 00278 .arg(suffix); 00279 00280 if (desc.longDescription != "") { 00281 selectedText += tr("<small>%1</small>") 00282 .arg(XmlExportable::encodeEntities(desc.longDescription)); 00283 } else if (desc.description != "") { 00284 selectedText += tr("<small>%1</small>") 00285 .arg(XmlExportable::encodeEntities(desc.description)); 00286 } 00287 00288 selectedText += tr("<small>"); 00289 if (desc.type != TransformDescription::UnknownType) { 00290 selectedText += tr("<br> — Plugin type: %1") 00291 .arg(XmlExportable::encodeEntities(factory->getTransformTypeName(desc.type))); 00292 } 00293 if (desc.category != "") { 00294 selectedText += tr("<br> — Category: %1") 00295 .arg(XmlExportable::encodeEntities(desc.category)); 00296 } 00297 selectedText += tr("<br> — System identifier: %1") 00298 .arg(XmlExportable::encodeEntities(desc.identifier)); 00299 if (desc.infoUrl != "") { 00300 selectedText += tr("<br> — More information: <a href=\"%1\">%1</a>") 00301 .arg(desc.infoUrl); 00302 } 00303 selectedText += tr("</small>"); 00304 00305 if (i >= (int)m_labels.size()) { 00306 SelectableLabel *label = new SelectableLabel(m_resultsFrame); 00307 m_resultsLayout->addWidget(label); 00308 connect(label, SIGNAL(selectionChanged()), this, 00309 SLOT(selectedLabelChanged())); 00310 connect(label, SIGNAL(doubleClicked()), this, 00311 SLOT(labelDoubleClicked())); 00312 QPalette palette = label->palette(); 00313 label->setPalette(palette); 00314 m_labels.push_back(label); 00315 } 00316 00317 m_labels[i]->setObjectName(desc.identifier); 00318 m_labels[i]->setFixedWidth(this->width() - 40); 00319 m_labels[i]->setUnselectedText(labelText); 00320 00321 // cerr << "selected text: " << selectedText << endl; 00322 m_labels[i]->setSelectedText(selectedText); 00323 00324 m_labels[i]->setSelected(m_selectedTransform == desc.identifier); 00325 00326 if (!m_labels[i]->isVisible()) m_labels[i]->show(); 00327 00328 ++m_upToDateCount; 00329 00330 if (i == 0) break; 00331 } 00332 00333 m_resultsFrame->resize(m_resultsFrame->sizeHint()); 00334 } 00335 00336 void 00337 TransformFinder::selectedLabelChanged() 00338 { 00339 QObject *s = sender(); 00340 m_selectedTransform = ""; 00341 for (int i = 0; i < (int)m_labels.size(); ++i) { 00342 if (!m_labels[i]->isVisible()) continue; 00343 if (m_labels[i] == s) { 00344 if (m_labels[i]->isSelected()) { 00345 m_selectedTransform = m_labels[i]->objectName(); 00346 } 00347 } else { 00348 if (m_labels[i]->isSelected()) { 00349 m_labels[i]->setSelected(false); 00350 } 00351 } 00352 } 00353 cerr << "selectedLabelChanged: selected transform is now \"" 00354 << m_selectedTransform << "\"" << endl; 00355 } 00356 00357 void 00358 TransformFinder::labelDoubleClicked() 00359 { 00360 // The first click should have selected the label already 00361 if (TransformFactory::getInstance()->getTransformInstallStatus 00362 (m_selectedTransform) == 00363 TransformFactory::TransformInstalled) { 00364 accept(); 00365 } 00366 } 00367 00368 TransformId 00369 TransformFinder::getTransform() const 00370 { 00371 return m_selectedTransform; 00372 } 00373 00374 void 00375 TransformFinder::up() 00376 { 00377 for (int i = 0; i < (int)m_labels.size(); ++i) { 00378 if (!m_labels[i]->isVisible()) continue; 00379 if (m_labels[i]->objectName() == m_selectedTransform) { 00380 if (i > 0) { 00381 m_labels[i]->setSelected(false); 00382 m_labels[i-1]->setSelected(true); 00383 m_selectedTransform = m_labels[i-1]->objectName(); 00384 } 00385 return; 00386 } 00387 } 00388 } 00389 00390 void 00391 TransformFinder::down() 00392 { 00393 for (int i = 0; i < (int)m_labels.size(); ++i) { 00394 if (!m_labels[i]->isVisible()) continue; 00395 if (m_labels[i]->objectName() == m_selectedTransform) { 00396 if (i+1 < (int)m_labels.size() && 00397 m_labels[i+1]->isVisible()) { 00398 m_labels[i]->setSelected(false); 00399 m_labels[i+1]->setSelected(true); 00400 m_selectedTransform = m_labels[i+1]->objectName(); 00401 } 00402 return; 00403 } 00404 } 00405 } 00406