File indexing completed on 2024-04-14 04:43:19
0001 /* AUDEX CDDA EXTRACTOR 0002 * SPDX-FileCopyrightText: Copyright (C) 2007 Marco Nelles 0003 * <https://userbase.kde.org/Audex> 0004 * 0005 * SPDX-License-Identifier: GPL-3.0-or-later 0006 */ 0007 0008 #include "mainwindow.h" 0009 #include "widgets/devicewidget.h" 0010 0011 #include <QMenu> 0012 #include <QWidgetAction> 0013 0014 class CDDATreeView : public QTreeView 0015 { 0016 public: 0017 CDDATreeView(QWidget *parent = nullptr) 0018 : QTreeView(parent) 0019 { 0020 } 0021 0022 protected: 0023 void closeEditor(QWidget *editor, QAbstractItemDelegate::EndEditHint hint) override 0024 { 0025 QTreeView::closeEditor(editor, hint); 0026 if ((this->currentIndex().row() < this->model()->rowCount() - 1) && (hint == QAbstractItemDelegate::SubmitModelCache)) { 0027 QTreeView::closeEditor(nullptr, QAbstractItemDelegate::EditNextItem); 0028 } 0029 } 0030 }; 0031 0032 MainWindow::MainWindow(QWidget *parent) 0033 : KXmlGuiWindow(parent) 0034 { 0035 profile_model = new ProfileModel(this); 0036 if (!profile_model) { 0037 qDebug() << "Unable to create ProfileModel object. Low mem?"; 0038 ErrorDialog::show(this, 0039 i18n("Unable to create ProfileModel object."), 0040 i18n("Internal error. Check your hardware. If all okay please make bug report.")); 0041 return; 0042 } 0043 if (profile_model->lastError().isValid()) { 0044 ErrorDialog::show(this, profile_model->lastError().message(), profile_model->lastError().details()); 0045 return; 0046 } 0047 0048 bool updated = firstStart(); 0049 0050 cdda_model = new CDDAModel(this); 0051 if (!cdda_model) { 0052 qDebug() << "Unable to create CDDAModel object. Low mem?"; 0053 ErrorDialog::show(this, i18n("Unable to create CDDAModel object."), i18n("Internal error. Check your hardware. If all okay please make bug report.")); 0054 return; 0055 } 0056 if (cdda_model->lastError().isValid()) { 0057 ErrorDialog::show(this, cdda_model->lastError().message(), cdda_model->lastError().details()); 0058 return; 0059 } 0060 0061 connect(cdda_model, SIGNAL(audioDiscDetected()), this, SLOT(new_audio_disc_detected())); 0062 connect(cdda_model, SIGNAL(audioDiscRemoved()), this, SLOT(audio_disc_removed())); 0063 0064 connect(cdda_model, SIGNAL(cddbLookupStarted()), this, SLOT(cddb_lookup_start())); 0065 connect(cdda_model, SIGNAL(cddbLookupDone(const bool)), this, SLOT(cddb_lookup_done(const bool))); 0066 connect(cdda_model, SIGNAL(cddbDataModified()), this, SLOT(enable_cddb_submit())); 0067 connect(cdda_model, SIGNAL(cddbDataModified()), this, SLOT(update_layout())); 0068 connect(cdda_model, SIGNAL(cddbDataSubmited(bool)), this, SLOT(enable_cddb_submit(bool))); 0069 0070 connect(profile_model, SIGNAL(profilesRemovedOrInserted()), this, SLOT(update_profile_action())); 0071 connect(profile_model, SIGNAL(currentProfileIndexChanged(int)), this, SLOT(update_profile_action(int))); 0072 0073 setup_actions(); 0074 setup_layout(); 0075 setupGUI(); 0076 0077 enable_layout(false); 0078 0079 if (updated) { 0080 update(); 0081 resize(650, 500); 0082 } 0083 0084 device_widget = nullptr; 0085 } 0086 0087 bool MainWindow::firstStart() 0088 { 0089 if (Preferences::firstStart()) { 0090 profile_model->autoCreate(); 0091 Preferences::setFirstStart(false); 0092 Preferences::self()->save(); 0093 return true; 0094 } 0095 0096 return false; 0097 } 0098 0099 MainWindow::~MainWindow() 0100 { 0101 delete profile_model; 0102 delete cdda_model; 0103 } 0104 0105 void MainWindow::eject() 0106 { 0107 qDebug() << "eject requested"; 0108 cdda_model->eject(); 0109 } 0110 0111 void MainWindow::cddb_lookup() 0112 { 0113 cdda_model->lookupCDDB(); 0114 } 0115 0116 void MainWindow::cddb_submit() 0117 { 0118 QStringList toc = cdda_model->cdio()->prettyTOC(); 0119 for (int i = 0; i < toc.size(); ++i) 0120 qDebug() << toc.at(i); 0121 return; 0122 if (!cdda_model->submitCDDB()) { 0123 ErrorDialog::show(this, cdda_model->lastError().message(), cdda_model->lastError().details()); 0124 } 0125 } 0126 0127 void MainWindow::rip() 0128 { 0129 if (cdda_model->empty()) { 0130 if (KMessageBox::warningTwoActions(this, 0131 i18n("No disc information set. Do you really want to continue?"), 0132 i18n("Disc information not found"), 0133 KStandardGuiItem::cont(), 0134 KStandardGuiItem::cancel(), 0135 "no_disc_info_warn") 0136 == KMessageBox::SecondaryAction) 0137 return; 0138 } 0139 0140 if ((profile_model->data(profile_model->index(profile_model->currentProfileRow(), PROFILE_MODEL_COLUMN_SF_INDEX)).toBool()) 0141 && (cdda_model->numOfAudioTracksInSelection() < cdda_model->numOfAudioTracks())) { 0142 if (KMessageBox::warningTwoActions(this, 0143 i18n("Single file rip selected but not all audio tracks to rip selected. Do you really want to continue?"), 0144 i18n("Not all audio tracks selected for single file rip"), 0145 KStandardGuiItem::cont(), 0146 KStandardGuiItem::cancel(), 0147 "singlefile_selection_warn") 0148 == KMessageBox::SecondaryAction) 0149 return; 0150 } 0151 0152 if ((profile_model->isSelectedEncoderWithEmbedCover() 0153 || (profile_model->data(profile_model->index(profile_model->currentProfileRow(), PROFILE_MODEL_COLUMN_SC_INDEX)).toBool())) 0154 && cdda_model->isCoverEmpty()) { 0155 if (KMessageBox::warningTwoActions(this, 0156 i18n("No cover was set. Do you really want to continue?"), 0157 i18n("Cover is empty"), 0158 KStandardGuiItem::cont(), 0159 KStandardGuiItem::cancel(), 0160 "empty_cover_warn") 0161 == KMessageBox::SecondaryAction) 0162 return; 0163 } 0164 0165 auto *dialog = new ExtractingProgressDialog(profile_model, cdda_model, this); 0166 0167 dialog->setWindowModality(Qt::ApplicationModal); 0168 0169 dialog->exec(); 0170 0171 delete dialog; 0172 } 0173 0174 void MainWindow::configure() 0175 { 0176 if (KConfigDialog::showDialog("settings")) 0177 return; 0178 0179 KConfigDialog *dialog = new KConfigDialog(this, "settings", Preferences::self()); 0180 0181 KPageWidgetItem *generalPage = dialog->addPage(new generalSettingsWidget(), i18n("General settings")); 0182 generalPage->setIcon(QIcon(QApplication::windowIcon())); 0183 0184 device_widget = new deviceWidget(); 0185 KPageWidgetItem *devicePage = dialog->addPage(device_widget, i18n("Device settings")); 0186 devicePage->setIcon(QIcon::fromTheme("drive-optical")); 0187 0188 if (cdda_model && cdda_model->cdio()) 0189 device_widget->setDeviceInfo(cdda_model->cdio()->getVendor(), 0190 cdda_model->cdio()->getModel(), 0191 cdda_model->cdio()->getRevision(), 0192 cdda_model->cdio()->getDriveCapabilities().contains(READ_MCN), 0193 cdda_model->cdio()->getDriveCapabilities().contains(READ_ISRC), 0194 cdda_model->cdio()->getDriveCapabilities().contains(C2_ERRS)); 0195 0196 KPageWidgetItem *profilePage = dialog->addPage(new profileWidget(profile_model), i18n("Profiles")); 0197 profilePage->setIcon(QIcon::fromTheme("document-multiple")); 0198 0199 KPluginMetaData info(QStringLiteral("plasma/kcms/systemsettings_qwidgets/kcm_cddb")); 0200 KCModule *m = KCModuleLoader::loadModule(info); 0201 if (m) { 0202 m->load(); 0203 auto *cfg = new KCDDB::Config(); 0204 cfg->load(); 0205 dialog->addPage(m->widget(), cfg, i18n("CDDB settings"), QStringLiteral("text-xmcd")); 0206 } 0207 0208 KPageWidgetItem *remoteServerPage = dialog->addPage(new remoteServerSettingsWidget(), i18n("Remote Server")); 0209 remoteServerPage->setIcon(QIcon::fromTheme("network-server")); 0210 0211 connect(dialog, SIGNAL(settingsChanged(const QString &)), this, SLOT(configuration_updated(const QString &))); 0212 0213 dialog->exec(); 0214 } 0215 0216 void MainWindow::edit() 0217 { 0218 cdda_header_widget->edit_data(); 0219 } 0220 0221 void MainWindow::new_audio_disc_detected() 0222 { 0223 enable_layout(true); 0224 resizeColumns(); 0225 if (Preferences::cddbLookupAuto()) { 0226 qDebug() << "Performing CDDB auto lookup"; 0227 QTimer::singleShot(0, this, SLOT(cddb_lookup())); 0228 } 0229 0230 update_layout(); 0231 0232 if (device_widget) { 0233 if (cdda_model && cdda_model->cdio()) { 0234 device_widget->setDeviceInfo(cdda_model->cdio()->getVendor(), 0235 cdda_model->cdio()->getModel(), 0236 cdda_model->cdio()->getRevision(), 0237 cdda_model->cdio()->getDriveCapabilities().contains(READ_MCN), 0238 cdda_model->cdio()->getDriveCapabilities().contains(READ_ISRC), 0239 cdda_model->cdio()->getDriveCapabilities().contains(C2_ERRS)); 0240 } else { 0241 device_widget->clearDeviceInfo(); 0242 } 0243 } 0244 } 0245 0246 void MainWindow::audio_disc_removed() 0247 { 0248 enable_layout(false); 0249 0250 update_layout(); 0251 0252 if (device_widget) 0253 device_widget->clearDeviceInfo(); 0254 } 0255 0256 void MainWindow::cddb_lookup_start() 0257 { 0258 } 0259 0260 void MainWindow::cddb_lookup_done(const bool successful) 0261 { 0262 if (!successful) { 0263 ErrorDialog::show(this, 0264 i18n("CDDB lookup failed, with the following error:\n%1", cdda_model->lastError().message()), 0265 cdda_model->lastError().details(), 0266 i18n("CDD Lookup Failure")); 0267 } 0268 update_layout(); 0269 disable_cddb_submit(); 0270 // if (Preferences::coverLookupAuto()) 0271 // cdda_header_widget->fetchCover(); 0272 } 0273 0274 void MainWindow::update_layout() 0275 { 0276 if (!cdda_model->isVarious()) { 0277 cdda_tree_view->hideColumn(CDDA_MODEL_COLUMN_ARTIST_INDEX); 0278 } else { 0279 cdda_tree_view->showColumn(CDDA_MODEL_COLUMN_ARTIST_INDEX); 0280 } 0281 resizeColumns(); 0282 actionCollection()->action("selectall")->setEnabled(cdda_model->selectedTracks().count() < cdda_model->numOfAudioTracks()); 0283 actionCollection()->action("selectnone")->setEnabled(cdda_model->selectedTracks().count() > 0); 0284 } 0285 0286 void MainWindow::enable_layout(bool enabled) 0287 { 0288 layout_enabled = enabled; 0289 cdda_tree_view->setEnabled(enabled); 0290 cdda_header_dock->setEnabled(enabled); 0291 cdda_header_widget->setEnabled(enabled); 0292 actionCollection()->action("profile_label")->setEnabled((profile_model->rowCount() > 0) && (enabled)); 0293 profile_combobox->setEnabled((profile_model->rowCount() > 0) && (enabled)); 0294 actionCollection()->action("profile")->setEnabled((profile_model->rowCount() > 0) && (enabled)); 0295 actionCollection()->action("cddbfetch")->setEnabled(enabled); 0296 if (cdda_model->isModified()) 0297 actionCollection()->action("cddbsubmit")->setEnabled(enabled); 0298 else 0299 actionCollection()->action("cddbsubmit")->setEnabled(false); 0300 actionCollection()->action("edit")->setEnabled(enabled); 0301 actionCollection()->action("eject")->setEnabled(enabled); 0302 actionCollection()->action("rip")->setEnabled(enabled); 0303 actionCollection()->action("splittitles")->setEnabled(enabled); 0304 actionCollection()->action("swapartistsandtitles")->setEnabled(enabled); 0305 actionCollection()->action("capitalize")->setEnabled(enabled); 0306 actionCollection()->action("autofillartists")->setEnabled(enabled); 0307 actionCollection()->action("selectall")->setEnabled(enabled); 0308 actionCollection()->action("selectnone")->setEnabled(enabled); 0309 actionCollection()->action("invertselection")->setEnabled(enabled); 0310 } 0311 0312 void MainWindow::enable_cddb_submit(bool enabled) 0313 { 0314 actionCollection()->action("cddbsubmit")->setEnabled(enabled); 0315 } 0316 0317 void MainWindow::disable_cddb_submit() 0318 { 0319 actionCollection()->action("cddbsubmit")->setEnabled(false); 0320 } 0321 0322 void MainWindow::configuration_updated(const QString &dialog_name) 0323 { 0324 Q_UNUSED(dialog_name); 0325 Preferences::self()->save(); 0326 } 0327 0328 void MainWindow::current_profile_updated_from_ui(int row) 0329 { 0330 if (row >= 0) { 0331 profile_model->blockSignals(true); 0332 profile_model->setRowAsCurrentProfileIndex(row); 0333 profile_model->blockSignals(false); 0334 } 0335 } 0336 0337 void MainWindow::update_profile_action(int index) 0338 { 0339 if (index == -1) { 0340 if (layout_enabled) { 0341 actionCollection()->action("profile_label")->setEnabled(false); 0342 actionCollection()->action("profile")->setEnabled(false); 0343 } 0344 } else { 0345 if (layout_enabled) { 0346 actionCollection()->action("profile_label")->setEnabled(true); 0347 actionCollection()->action("profile")->setEnabled(true); 0348 } 0349 profile_combobox->setCurrentIndex(profile_model->getRowByIndex(index)); 0350 } 0351 } 0352 0353 void MainWindow::update_profile_action() 0354 { 0355 // When the Profile model emits 'reset' the profile combo clears its current settings. 0356 // Therefore, we need to try and reset these... 0357 if (profile_combobox->currentText().isEmpty()) { 0358 profile_combobox->setCurrentIndex(profile_model->currentProfileRow()); 0359 } 0360 0361 if (layout_enabled) { 0362 actionCollection()->action("profile_label")->setEnabled(profile_model->rowCount() > 0); 0363 actionCollection()->action("profile")->setEnabled(profile_model->rowCount() > 0); 0364 } 0365 } 0366 0367 void MainWindow::split_titles() 0368 { 0369 bool ok; 0370 QString divider = QInputDialog::getText(this, 0371 i18n("Split titles"), 0372 i18n("Please set a divider string. Be aware of empty spaces.\n\nDivider:"), 0373 QLineEdit::Normal, 0374 " - ", 0375 &ok); 0376 if (ok && !divider.isEmpty()) { 0377 cdda_model->splitTitleOfTracks(divider); 0378 } 0379 } 0380 0381 void MainWindow::swap_artists_and_titles() 0382 { 0383 if (KMessageBox::warningTwoActions(this, 0384 i18n("Do you really want to swap all artists and titles?"), 0385 i18n("Swap artists and titles"), 0386 KStandardGuiItem::ok(), 0387 KStandardGuiItem::cancel(), 0388 "no_swap_artists_and_titles_warn") 0389 == KMessageBox::SecondaryAction) 0390 return; 0391 0392 cdda_model->swapArtistAndTitle(); 0393 cdda_model->swapArtistAndTitleOfTracks(); 0394 } 0395 0396 void MainWindow::capitalize() 0397 { 0398 if (KMessageBox::warningTwoActions(this, 0399 i18n("Do you really want to capitalize all artists and titles?"), 0400 i18n("Capitalize artists and titles"), 0401 KStandardGuiItem::ok(), 0402 KStandardGuiItem::cancel(), 0403 "no_capitalize_warn") 0404 == KMessageBox::SecondaryAction) 0405 return; 0406 0407 cdda_model->capitalizeHeader(); 0408 cdda_model->capitalizeTracks(); 0409 } 0410 0411 void MainWindow::auto_fill_artists() 0412 { 0413 if (KMessageBox::warningTwoActions(this, 0414 i18n("Do you really want to autofill track artists?"), 0415 i18n("Autofill artists"), 0416 KStandardGuiItem::ok(), 0417 KStandardGuiItem::cancel(), 0418 "no_autofill_warn") 0419 == KMessageBox::SecondaryAction) 0420 return; 0421 0422 cdda_model->setTitleArtistsFromHeader(); 0423 } 0424 0425 void MainWindow::toggle(const QModelIndex &idx) 0426 { 0427 if (idx.isValid() && (idx.column() == CDDA_MODEL_COLUMN_RIP_INDEX)) { 0428 cdda_model->toggle(idx.row()); 0429 cdda_tree_view->update(idx); 0430 } 0431 } 0432 0433 void MainWindow::resizeColumns() 0434 { 0435 for (int i = 0; i < CDDA_MODEL_COLUMN_COUNT; ++i) 0436 cdda_tree_view->resizeColumnToContents(i); 0437 } 0438 0439 void MainWindow::setup_actions() 0440 { 0441 auto *ejectAction = new QAction(this); 0442 ejectAction->setText(i18n("Eject")); 0443 ejectAction->setIcon(QIcon::fromTheme("media-eject")); 0444 actionCollection()->addAction("eject", ejectAction); 0445 actionCollection()->setDefaultShortcut(ejectAction, Qt::CTRL + Qt::Key_E); 0446 connect(ejectAction, SIGNAL(triggered(bool)), this, SLOT(eject())); 0447 0448 profile_label = new QLabel(this); 0449 profile_label->setText(i18n("Profile:")); 0450 profile_combobox = new KComboBox(this); 0451 profile_combobox->setModel(profile_model); 0452 profile_combobox->setModelColumn(1); 0453 profile_combobox->setMinimumWidth(80); 0454 profile_combobox->setMaximumWidth(220); 0455 profile_combobox->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed)); 0456 profile_combobox->resize(QSize(220, profile_combobox->height())); 0457 profile_combobox->setCurrentIndex(profile_model->currentProfileRow()); 0458 connect(profile_combobox, SIGNAL(currentIndexChanged(int)), this, SLOT(current_profile_updated_from_ui(int))); 0459 0460 auto *plabelAction = new QWidgetAction(this); 0461 plabelAction->setText(i18n("&Profile:")); 0462 plabelAction->setDefaultWidget(profile_label); 0463 profile_label->setBuddy(profile_combobox); 0464 actionCollection()->addAction("profile_label", plabelAction); 0465 0466 auto *profileAction = new QWidgetAction(this); 0467 profileAction->setText(i18n("Profile")); 0468 profileAction->setDefaultWidget(profile_combobox); 0469 actionCollection()->addAction("profile", profileAction); 0470 actionCollection()->setDefaultShortcut(profileAction, Qt::Key_F6); 0471 actionCollection()->setShortcutsConfigurable(profileAction, false); 0472 update_profile_action(); 0473 0474 auto *cddbLookupAction = new QAction(this); 0475 cddbLookupAction->setText(i18n("Fetch")); 0476 cddbLookupAction->setIcon(QIcon::fromTheme("view-list-text")); 0477 actionCollection()->addAction("cddbfetch", cddbLookupAction); 0478 actionCollection()->setDefaultShortcut(cddbLookupAction, Qt::CTRL + Qt::Key_F); 0479 connect(cddbLookupAction, SIGNAL(triggered(bool)), this, SLOT(cddb_lookup())); 0480 0481 auto *cddbSubmitAction = new QAction(this); 0482 cddbSubmitAction->setText(i18n("Submit")); 0483 actionCollection()->addAction("cddbsubmit", cddbSubmitAction); 0484 actionCollection()->setDefaultShortcut(cddbSubmitAction, Qt::CTRL + Qt::Key_S); 0485 connect(cddbSubmitAction, SIGNAL(triggered(bool)), this, SLOT(cddb_submit())); 0486 0487 auto *editAction = new QAction(this); 0488 editAction->setText(i18n("Edit")); 0489 editAction->setIcon(QIcon::fromTheme("document-edit")); 0490 actionCollection()->addAction("edit", editAction); 0491 actionCollection()->setDefaultShortcut(editAction, Qt::CTRL + Qt::Key_D); 0492 connect(editAction, SIGNAL(triggered(bool)), this, SLOT(edit())); 0493 0494 auto *extractAction = new QAction(this); 0495 extractAction->setText(i18n("Rip...")); 0496 extractAction->setIcon(QIcon::fromTheme("media-optical-audio")); 0497 actionCollection()->addAction("rip", extractAction); 0498 actionCollection()->setDefaultShortcut(extractAction, Qt::CTRL + Qt::Key_X); 0499 connect(extractAction, SIGNAL(triggered(bool)), this, SLOT(rip())); 0500 0501 actionCollection()->addAction("preferences", KStandardAction::preferences(this, SLOT(configure()), this)); 0502 0503 auto *splitTitlesAction = new QAction(this); 0504 splitTitlesAction->setText(i18n("Split Titles...")); 0505 actionCollection()->addAction("splittitles", splitTitlesAction); 0506 connect(splitTitlesAction, SIGNAL(triggered(bool)), this, SLOT(split_titles())); 0507 0508 auto *swapArtistsAndTitlesAction = new QAction(this); 0509 swapArtistsAndTitlesAction->setText(i18n("Swap Artists And Titles")); 0510 actionCollection()->addAction("swapartistsandtitles", swapArtistsAndTitlesAction); 0511 connect(swapArtistsAndTitlesAction, SIGNAL(triggered(bool)), this, SLOT(swap_artists_and_titles())); 0512 0513 auto *capitalizeAction = new QAction(this); 0514 capitalizeAction->setText(i18n("Capitalize")); 0515 actionCollection()->addAction("capitalize", capitalizeAction); 0516 connect(capitalizeAction, SIGNAL(triggered(bool)), this, SLOT(capitalize())); 0517 0518 auto *autoFillArtistsAction = new QAction(this); 0519 autoFillArtistsAction->setText(i18n("Auto Fill Artists")); 0520 actionCollection()->addAction("autofillartists", autoFillArtistsAction); 0521 connect(autoFillArtistsAction, SIGNAL(triggered(bool)), this, SLOT(auto_fill_artists())); 0522 0523 auto *selectAllAction = new QAction(this); 0524 selectAllAction->setText(i18n("Select All Tracks")); 0525 actionCollection()->addAction("selectall", selectAllAction); 0526 connect(selectAllAction, SIGNAL(triggered(bool)), this, SLOT(select_all())); 0527 0528 auto *selectNoneAction = new QAction(this); 0529 selectNoneAction->setText(i18n("Deselect All Tracks")); 0530 actionCollection()->addAction("selectnone", selectNoneAction); 0531 connect(selectNoneAction, SIGNAL(triggered(bool)), this, SLOT(select_none())); 0532 0533 auto *invertSelectionAction = new QAction(this); 0534 invertSelectionAction->setText(i18n("Invert Selection")); 0535 actionCollection()->addAction("invertselection", invertSelectionAction); 0536 connect(invertSelectionAction, SIGNAL(triggered(bool)), this, SLOT(invert_selection())); 0537 0538 KStandardAction::quit(qApp, SLOT(quit()), actionCollection()); 0539 } 0540 0541 void MainWindow::setup_layout() 0542 { 0543 cdda_tree_view = new CDDATreeView(this); 0544 cdda_tree_view->setModel(cdda_model); 0545 cdda_tree_view->setAlternatingRowColors(true); 0546 cdda_tree_view->setSelectionBehavior(QAbstractItemView::SelectRows); 0547 cdda_tree_view->setEditTriggers(QAbstractItemView::EditKeyPressed | QAbstractItemView::DoubleClicked); 0548 cdda_tree_view->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding); 0549 cdda_tree_view->setIndentation(0); 0550 cdda_tree_view->setAllColumnsShowFocus(true); 0551 cdda_tree_view->setContextMenuPolicy(Qt::CustomContextMenu); 0552 connect(cdda_tree_view, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(cdda_context_menu(const QPoint &))); 0553 connect(cdda_tree_view, SIGNAL(clicked(const QModelIndex &)), SLOT(toggle(const QModelIndex &))); 0554 connect(cdda_model, SIGNAL(selectionChanged(const int)), this, SLOT(selection_changed(const int))); 0555 0556 cdda_header_dock = new QDockWidget(this); 0557 cdda_header_dock->setObjectName("cdda_header_dock"); 0558 cdda_header_dock->setFeatures(QDockWidget::DockWidgetMovable | QDockWidget::DockWidgetFloatable); 0559 cdda_header_dock->setAllowedAreas(Qt::AllDockWidgetAreas); 0560 0561 setCentralWidget(cdda_tree_view); 0562 cdda_header_widget = new CDDAHeaderWidget(cdda_model, cdda_header_dock); 0563 connect(cdda_header_widget, SIGNAL(headerDataChanged()), this, SLOT(update_layout())); 0564 cdda_header_dock->setWidget(cdda_header_widget); 0565 addDockWidget(Qt::LeftDockWidgetArea, cdda_header_dock); 0566 0567 statusBar()->hide(); 0568 statusBar()->setMaximumHeight(0); 0569 } 0570 0571 void MainWindow::select_all() 0572 { 0573 cdda_model->selectAll(); 0574 } 0575 0576 void MainWindow::select_none() 0577 { 0578 cdda_model->selectNone(); 0579 } 0580 0581 void MainWindow::invert_selection() 0582 { 0583 cdda_model->invertSelection(); 0584 } 0585 0586 void MainWindow::cdda_context_menu(const QPoint &pos) 0587 { 0588 Q_UNUSED(pos); 0589 QMenu menu(this); 0590 menu.addAction(actionCollection()->action("selectall")); 0591 menu.addAction(actionCollection()->action("selectnone")); 0592 menu.addSeparator(); 0593 menu.addAction(actionCollection()->action("invertselection")); 0594 menu.exec(QCursor::pos()); 0595 } 0596 0597 void MainWindow::selection_changed(const int num_selected) 0598 { 0599 actionCollection()->action("rip")->setEnabled(num_selected > 0); 0600 actionCollection()->action("selectall")->setEnabled(num_selected < cdda_model->numOfAudioTracks()); 0601 actionCollection()->action("selectnone")->setEnabled(num_selected > 0); 0602 }