annotate widgets/TransformFinder.cpp @ 448:2b5d04b21d87

* Add some informative labels to transform finder
author Chris Cannam
date Wed, 19 Nov 2008 14:55:17 +0000
parents f8fcfbe13c8f
children f2ef0ff2e3b0
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@448 51 m_infoLabel = new QLabel(tr("Type in the box above to search descriptions of available and known transforms"));
Chris@448 52 mainGrid->addWidget(m_infoLabel, 1, 1);
Chris@448 53
Chris@416 54 m_resultsScroll = new QScrollArea;
Chris@448 55 mainGrid->addWidget(m_resultsScroll, 2, 0, 1, 2);
Chris@448 56 mainGrid->setRowStretch(2, 10);
Chris@416 57
Chris@416 58 QDialogButtonBox *bb = new QDialogButtonBox(QDialogButtonBox::Ok |
Chris@416 59 QDialogButtonBox::Cancel);
Chris@448 60 mainGrid->addWidget(bb, 3, 0, 1, 2);
Chris@416 61 connect(bb, SIGNAL(accepted()), this, SLOT(accept()));
Chris@416 62 connect(bb, SIGNAL(rejected()), this, SLOT(reject()));
Chris@448 63
Chris@448 64 m_resultsFrame = new QWidget;
Chris@448 65 QPalette palette = m_resultsFrame->palette();
Chris@448 66 palette.setColor(QPalette::Window, palette.color(QPalette::Base));
Chris@448 67 m_resultsFrame->setPalette(palette);
Chris@448 68 m_resultsScroll->setPalette(palette);
Chris@448 69 m_resultsLayout = new QVBoxLayout;
Chris@448 70 m_resultsLayout->setSpacing(0);
Chris@448 71 m_resultsLayout->setContentsMargins(0, 0, 0, 0);
Chris@448 72 m_resultsFrame->setLayout(m_resultsLayout);
Chris@448 73 m_resultsScroll->setWidget(m_resultsFrame);
Chris@448 74 m_resultsFrame->show();
Chris@448 75
Chris@448 76 m_noResultsLabel = new QLabel(tr("<br>&nbsp;&nbsp;No results found"));
Chris@448 77 m_resultsLayout->addWidget(m_noResultsLabel);
Chris@448 78 m_noResultsLabel->hide();
Chris@448 79
Chris@448 80 m_beforeSearchLabel = new QLabel;
Chris@448 81 m_resultsLayout->addWidget(m_beforeSearchLabel);
Chris@448 82 m_beforeSearchLabel->hide();
Chris@416 83
Chris@426 84 QAction *up = new QAction(tr("Up"), this);
Chris@426 85 up->setShortcut(tr("Up"));
Chris@426 86 connect(up, SIGNAL(triggered()), this, SLOT(up()));
Chris@426 87 addAction(up);
Chris@426 88
Chris@426 89 QAction *down = new QAction(tr("Down"), this);
Chris@426 90 down->setShortcut(tr("Down"));
Chris@426 91 connect(down, SIGNAL(triggered()), this, SLOT(down()));
Chris@426 92 addAction(down);
Chris@426 93
Chris@423 94 QDesktopWidget *desktop = QApplication::desktop();
Chris@423 95 QRect available = desktop->availableGeometry();
Chris@423 96
Chris@423 97 int width = available.width() / 2;
Chris@423 98 int height = available.height() / 2;
Chris@423 99 if (height < 450) {
Chris@423 100 if (available.height() > 500) height = 450;
Chris@423 101 }
Chris@423 102 if (width < 600) {
Chris@423 103 if (available.width() > 650) width = 600;
Chris@423 104 }
Chris@423 105
Chris@423 106 resize(width, height);
Chris@423 107 raise();
Chris@424 108
Chris@424 109 m_upToDateCount = 0;
Chris@424 110 m_timer = new QTimer(this);
Chris@424 111 connect(m_timer, SIGNAL(timeout()), this, SLOT(timeout()));
Chris@425 112 m_timer->start(30);
Chris@416 113 }
Chris@416 114
Chris@416 115 TransformFinder::~TransformFinder()
Chris@416 116 {
Chris@416 117 }
Chris@416 118
Chris@416 119 void
Chris@416 120 TransformFinder::searchTextChanged(const QString &text)
Chris@416 121 {
Chris@448 122 // std::cerr << "text is " << text.toStdString() << std::endl;
Chris@424 123 m_newSearchText = text;
Chris@424 124 }
Chris@416 125
Chris@424 126 void
Chris@424 127 TransformFinder::timeout()
Chris@424 128 {
Chris@448 129 int maxResults = 60;
Chris@416 130
Chris@424 131 if (m_newSearchText != "") {
Chris@416 132
Chris@424 133 QString text = m_newSearchText;
Chris@424 134 m_newSearchText = "";
Chris@424 135
Chris@424 136 QStringList keywords = text.split(' ', QString::SkipEmptyParts);
Chris@424 137 TransformFactory::SearchResults results =
Chris@424 138 TransformFactory::getInstance()->search(keywords);
Chris@424 139
Chris@448 140 // std::cerr << results.size() << " result(s)..." << std::endl;
Chris@424 141
Chris@431 142 std::set<TextMatcher::Match> sorted;
Chris@424 143 sorted.clear();
Chris@424 144 for (TransformFactory::SearchResults::const_iterator j = results.begin();
Chris@424 145 j != results.end(); ++j) {
Chris@424 146 sorted.insert(j->second);
Chris@424 147 }
Chris@448 148
Chris@424 149 m_sortedResults.clear();
Chris@431 150 for (std::set<TextMatcher::Match>::const_iterator j = sorted.end();
Chris@424 151 j != sorted.begin(); ) {
Chris@424 152 --j;
Chris@424 153 m_sortedResults.push_back(*j);
Chris@424 154 if (m_sortedResults.size() == maxResults) break;
Chris@424 155 }
Chris@424 156
Chris@424 157 if (m_sortedResults.empty()) m_selectedTransform = "";
Chris@431 158 else m_selectedTransform = m_sortedResults.begin()->key;
Chris@424 159
Chris@424 160 m_upToDateCount = 0;
Chris@424 161
Chris@424 162 for (int j = m_labels.size(); j > m_sortedResults.size(); ) {
Chris@424 163 m_labels[--j]->hide();
Chris@424 164 }
Chris@424 165
Chris@448 166 if (m_sortedResults.empty()) {
Chris@448 167 m_noResultsLabel->show();
Chris@448 168 m_resultsFrame->resize(m_resultsFrame->sizeHint());
Chris@448 169 } else {
Chris@448 170 m_noResultsLabel->hide();
Chris@448 171 }
Chris@448 172
Chris@448 173 if (m_sortedResults.size() < sorted.size()) {
Chris@448 174 m_infoLabel->setText
Chris@448 175 (tr("Found %n description(s) containing <b>%1</b>, showing the first %2 only",
Chris@448 176 0, sorted.size()).arg(text).arg(m_sortedResults.size()));
Chris@448 177 } else {
Chris@448 178 m_infoLabel->setText
Chris@448 179 (tr("Found %n description(s) containing <b>%1</b>",
Chris@448 180 0, sorted.size()).arg(text));
Chris@448 181 }
Chris@448 182
Chris@424 183 return;
Chris@416 184 }
Chris@416 185
Chris@425 186 if (m_upToDateCount >= m_sortedResults.size()) return;
Chris@425 187
Chris@425 188 while (m_upToDateCount < m_sortedResults.size()) {
Chris@417 189
Chris@424 190 int i = m_upToDateCount;
Chris@416 191
Chris@431 192 // std::cerr << "sorted size = " << m_sortedResults.size() << std::endl;
Chris@417 193
Chris@431 194 TransformDescription desc;
Chris@431 195 TransformId tid = m_sortedResults[i].key;
Chris@431 196 TransformFactory *factory = TransformFactory::getInstance();
Chris@431 197 TransformFactory::TransformInstallStatus status =
Chris@431 198 factory->getTransformInstallStatus(tid);
Chris@431 199 QString suffix;
Chris@431 200
Chris@431 201 if (status == TransformFactory::TransformInstalled) {
Chris@431 202 desc = factory->getTransformDescription(tid);
Chris@431 203 } else {
Chris@431 204 desc = factory->getUninstalledTransformDescription(tid);
Chris@431 205 suffix = tr("<i> (not installed)</i>");
Chris@431 206 }
Chris@419 207
Chris@419 208 QString labelText;
Chris@431 209 labelText += tr("%1%2<br><small>")
Chris@431 210 .arg(XmlExportable::encodeEntities(desc.name))
Chris@431 211 .arg(suffix);
Chris@424 212
Chris@416 213 labelText += "...";
Chris@431 214 for (TextMatcher::Match::FragmentMap::const_iterator k =
Chris@424 215 m_sortedResults[i].fragments.begin();
Chris@424 216 k != m_sortedResults[i].fragments.end(); ++k) {
Chris@416 217 labelText += k->second;
Chris@416 218 labelText += "... ";
Chris@416 219 }
Chris@416 220 labelText += tr("</small>");
Chris@417 221
Chris@419 222 QString selectedText;
Chris@431 223 selectedText += tr("<b>%1</b>%2<br>")
Chris@431 224 .arg(XmlExportable::encodeEntities
Chris@431 225 (desc.name == "" ? desc.identifier : desc.name))
Chris@431 226 .arg(suffix);
Chris@431 227
Chris@431 228 if (desc.longDescription != "") {
Chris@431 229 selectedText += tr("<small>%1</small>")
Chris@431 230 .arg(XmlExportable::encodeEntities(desc.longDescription));
Chris@431 231 } else if (desc.description != "") {
Chris@431 232 selectedText += tr("<small>%1</small>")
Chris@431 233 .arg(XmlExportable::encodeEntities(desc.description));
Chris@431 234 }
Chris@419 235
Chris@436 236 selectedText += tr("<small>");
Chris@431 237 if (desc.type != "") {
Chris@436 238 selectedText += tr("<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&mdash; Plugin type: %1")
Chris@431 239 .arg(XmlExportable::encodeEntities(desc.type));
Chris@431 240 }
Chris@431 241 if (desc.category != "") {
Chris@436 242 selectedText += tr("<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&mdash; Category: %1")
Chris@431 243 .arg(XmlExportable::encodeEntities(desc.category));
Chris@431 244 }
Chris@436 245 selectedText += tr("<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&mdash; System identifier: %1")
Chris@424 246 .arg(XmlExportable::encodeEntities(desc.identifier));
Chris@436 247 if (desc.infoUrl != "") {
Chris@436 248 selectedText += tr("<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&mdash; More information: <a href=\"%1\">%1</a>")
Chris@436 249 .arg(desc.infoUrl);
Chris@436 250 }
Chris@426 251 selectedText += tr("</small>");
Chris@419 252
Chris@417 253 if (i >= m_labels.size()) {
Chris@419 254 SelectableLabel *label = new SelectableLabel(m_resultsFrame);
Chris@421 255 m_resultsLayout->addWidget(label);
Chris@420 256 connect(label, SIGNAL(selectionChanged()), this,
Chris@420 257 SLOT(selectedLabelChanged()));
Chris@424 258 connect(label, SIGNAL(doubleClicked()), this,
Chris@448 259 SLOT(labelDoubleClicked()));
Chris@421 260 QPalette palette = label->palette();
Chris@421 261 label->setPalette(palette);
Chris@417 262 m_labels.push_back(label);
Chris@417 263 }
Chris@421 264
Chris@420 265 m_labels[i]->setObjectName(desc.identifier);
Chris@423 266 m_labels[i]->setFixedWidth(this->width() - 40);
Chris@419 267 m_labels[i]->setUnselectedText(labelText);
Chris@425 268
Chris@425 269 // std::cerr << "selected text: " << selectedText.toStdString() << std::endl;
Chris@419 270 m_labels[i]->setSelectedText(selectedText);
Chris@423 271
Chris@424 272 m_labels[i]->setSelected(m_selectedTransform == desc.identifier);
Chris@425 273
Chris@425 274 if (!m_labels[i]->isVisible()) m_labels[i]->show();
Chris@417 275
Chris@424 276 ++m_upToDateCount;
Chris@424 277
Chris@425 278 if (i == 0) break;
Chris@416 279 }
Chris@425 280
Chris@425 281 m_resultsFrame->resize(m_resultsFrame->sizeHint());
Chris@416 282 }
Chris@416 283
Chris@420 284 void
Chris@420 285 TransformFinder::selectedLabelChanged()
Chris@420 286 {
Chris@420 287 QObject *s = sender();
Chris@420 288 m_selectedTransform = "";
Chris@420 289 for (int i = 0; i < m_labels.size(); ++i) {
Chris@420 290 if (!m_labels[i]->isVisible()) continue;
Chris@420 291 if (m_labels[i] == s) {
Chris@420 292 if (m_labels[i]->isSelected()) {
Chris@420 293 m_selectedTransform = m_labels[i]->objectName();
Chris@420 294 }
Chris@420 295 } else {
Chris@420 296 if (m_labels[i]->isSelected()) {
Chris@420 297 m_labels[i]->setSelected(false);
Chris@420 298 }
Chris@420 299 }
Chris@420 300 }
Chris@420 301 std::cerr << "selectedLabelChanged: selected transform is now \""
Chris@420 302 << m_selectedTransform.toStdString() << "\"" << std::endl;
Chris@420 303 }
Chris@420 304
Chris@448 305 void
Chris@448 306 TransformFinder::labelDoubleClicked()
Chris@448 307 {
Chris@448 308 // The first click should have selected the label already
Chris@448 309 if (TransformFactory::getInstance()->getTransformInstallStatus
Chris@448 310 (m_selectedTransform) ==
Chris@448 311 TransformFactory::TransformInstalled) {
Chris@448 312 accept();
Chris@448 313 }
Chris@448 314 }
Chris@448 315
Chris@416 316 TransformId
Chris@416 317 TransformFinder::getTransform() const
Chris@416 318 {
Chris@424 319 return m_selectedTransform;
Chris@416 320 }
Chris@416 321
Chris@426 322 void
Chris@426 323 TransformFinder::up()
Chris@426 324 {
Chris@426 325 for (int i = 0; i < m_labels.size(); ++i) {
Chris@426 326 if (!m_labels[i]->isVisible()) continue;
Chris@426 327 if (m_labels[i]->objectName() == m_selectedTransform) {
Chris@426 328 if (i > 0) {
Chris@426 329 m_labels[i]->setSelected(false);
Chris@426 330 m_labels[i-1]->setSelected(true);
Chris@426 331 m_selectedTransform = m_labels[i-1]->objectName();
Chris@426 332 }
Chris@426 333 return;
Chris@426 334 }
Chris@426 335 }
Chris@426 336 }
Chris@426 337
Chris@426 338 void
Chris@426 339 TransformFinder::down()
Chris@426 340 {
Chris@426 341 for (int i = 0; i < m_labels.size(); ++i) {
Chris@426 342 if (!m_labels[i]->isVisible()) continue;
Chris@426 343 if (m_labels[i]->objectName() == m_selectedTransform) {
Chris@426 344 if (i+1 < m_labels.size() &&
Chris@426 345 m_labels[i+1]->isVisible()) {
Chris@426 346 m_labels[i]->setSelected(false);
Chris@426 347 m_labels[i+1]->setSelected(true);
Chris@426 348 m_selectedTransform = m_labels[i+1]->objectName();
Chris@426 349 }
Chris@426 350 return;
Chris@426 351 }
Chris@426 352 }
Chris@426 353 }
Chris@426 354