1 /** 2 * \file basemainwindow.h 3 * Base class for main window. 4 * 5 * \b Project: Kid3 6 * \author Urs Fleisch 7 * \date 9 Jan 2003 8 * 9 * Copyright (C) 2003-2018 Urs Fleisch 10 * 11 * This file is part of Kid3. 12 * 13 * Kid3 is free software; you can redistribute it and/or modify 14 * it under the terms of the GNU General Public License as published by 15 * the Free Software Foundation; either version 2 of the License, or 16 * (at your option) any later version. 17 * 18 * Kid3 is distributed in the hope that it will be useful, 19 * but WITHOUT ANY WARRANTY; without even the implied warranty of 20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 21 * GNU General Public License for more details. 22 * 23 * You should have received a copy of the GNU General Public License 24 * along with this program. If not, see <http://www.gnu.org/licenses/>. 25 */ 26 27 #pragma once 28 29 #include <QMainWindow> 30 #include <QDateTime> 31 #include <QScopedPointer> 32 #include "iframeeditor.h" 33 #include "frame.h" 34 #include "kid3api.h" 35 36 class QLabel; 37 class QProgressBar; 38 class QToolButton; 39 class QItemSelection; 40 class QTimer; 41 class ProgressWidget; 42 class Kid3Form; 43 class Kid3Application; 44 class TaggedFile; 45 class ImportDialog; 46 class TagImportDialog; 47 class BatchImportDialog; 48 class ExportDialog; 49 class FindReplaceDialog; 50 class BrowseCoverArtDialog; 51 class RenDirDialog; 52 class NumberTracksDialog; 53 class RenDirDialog; 54 class FilterDialog; 55 class FileFilter; 56 class DownloadDialog; 57 class PlaylistDialog; 58 class PlaylistEditDialog; 59 class PlaylistConfig; 60 class EditFrameFieldsDialog; 61 class PlayToolBar; 62 class DirContents; 63 class FileProxyModel; 64 class DirProxyModel; 65 class TrackDataModel; 66 class IPlatformTools; 67 class BaseMainWindow; 68 69 /** 70 * Implementation class for BaseMainWindow. 71 * The reason for this implementation class is that a QObject is needed to 72 * have slots. However, BaseMainWindow cannot inherit from QObject because it 73 * is used with multiple inheritance together with another class which is a 74 * QObject (actually a QMainWindow). Therefore the functionality of the main 75 * put into this class which is then used as an implementation class by 76 * BaseMainWindow. 77 */ 78 class KID3_GUI_EXPORT BaseMainWindowImpl : public QObject, public IFrameEditor { 79 Q_OBJECT 80 public: 81 /** 82 * Constructor. 83 * 84 * @param mainWin main window widget 85 * @param platformTools platform specific tools 86 */ 87 BaseMainWindowImpl(QMainWindow* mainWin, IPlatformTools* platformTools, Kid3Application *app); 88 89 /** 90 * Destructor. 91 */ 92 virtual ~BaseMainWindowImpl() override; 93 94 /** 95 * Create dialog to edit a frame and update the fields 96 * if Ok is returned. 97 * frameEdited() is emitted when the edit dialog is closed with the edited 98 * frame as a parameter if it was accepted. 99 * 100 * @param frame frame to edit 101 * @param taggedFile tagged file where frame has to be set 102 */ 103 virtual void editFrameOfTaggedFile(const Frame* frame, TaggedFile* taggedFile) override; 104 105 /** 106 * Let user select a frame type. 107 * frameSelected() is emitted when the edit dialog is closed with the selected 108 * frame as a parameter if a frame is selected. 109 * 110 * @param frame is filled with the selected frame 111 * @param taggedFile tagged file for which frame has to be selected 112 */ 113 virtual void selectFrame(Frame* frame, const TaggedFile* taggedFile) override; 114 115 /** 116 * Return object which emits frameSelected(), frameEdited() signals. 117 * 118 * @return object which emits signals. 119 */ 120 virtual QObject* qobject() override; 121 122 /** 123 * Get the tag number of the edited frame. 124 * @return tag number. 125 */ 126 virtual Frame::TagNumber tagNumber() const override; 127 128 /** 129 * Set the tag number of the edited frame. 130 * @param tagNr tag number 131 */ 132 virtual void setTagNumber(Frame::TagNumber tagNr) override; 133 134 /** 135 * Set back pointer for implementation class. 136 * 137 * @param self back pointer 138 */ setBackPointer(BaseMainWindow * self)139 void setBackPointer(BaseMainWindow* self) { m_self = self; } 140 141 /** 142 * Initialize main window. 143 * Shall be called at end of constructor body. 144 */ 145 void init(); 146 147 /** 148 * Change visibility of status bar. 149 * @param visible true to show status bar 150 */ 151 void setStatusBarVisible(bool visible); 152 153 /** 154 * Update modification state before closing. 155 * If anything was modified, save after asking user. 156 * Save options before closing. 157 * This method shall be called by closeEvent() (Qt) or 158 * queryClose() (KDE). 159 * 160 * @return false if user canceled, 161 * true will quit the application. 162 */ 163 bool queryBeforeClosing(); 164 165 /** 166 * Open recent directory. 167 * 168 * @param dir directory to open 169 */ 170 void openRecentDirectory(const QString& dir); 171 172 /** 173 * Apply configuration changes. 174 */ 175 void applyChangedConfiguration(); 176 177 /** 178 * Apply keyboard shortcut changes. 179 */ 180 void applyChangedShortcuts(); 181 182 /** 183 * Access to application. 184 * @return application. 185 */ app()186 Kid3Application* app() { return m_app; } 187 188 /** 189 * Access to main form. 190 * @return main form. 191 */ form()192 Kid3Form* form() { return m_form; } 193 194 public slots: 195 /** 196 * Set window title with information from directory, filter and modification 197 * state. 198 */ 199 void updateWindowCaption(); 200 201 /** 202 * Open directory, user has to confirm if current directory modified. 203 * 204 * @param paths directory or file paths 205 */ 206 void confirmedOpenDirectory(const QStringList& paths); 207 208 /** 209 * Update the recent file list and the caption when a new directory 210 * is opened. 211 */ 212 void onDirectoryOpened(); 213 214 /** 215 * Request new directory and open it. 216 */ 217 void slotFileOpen(); 218 219 /** 220 * Request new directory and open it. 221 */ 222 void slotFileOpenDirectory(); 223 224 /** 225 * Reload the current directory. 226 */ 227 void slotFileReload(); 228 229 /** 230 * Save modified files. 231 */ 232 void slotFileSave(); 233 234 /** 235 * Quit application. 236 */ 237 void slotFileQuit(); 238 239 /** 240 * Change status message. 241 * 242 * @param text message 243 */ 244 void slotStatusMsg(const QString& text); 245 246 /** 247 * Clear status message. 248 * To be called when a message set with slotStatusMsg() is no longer valid. 249 */ 250 void slotClearStatusMsg(); 251 252 /** 253 * Show playlist dialog. 254 */ 255 void slotPlaylistDialog(); 256 257 /** 258 * Create playlist. 259 * 260 * @return true if ok. 261 */ 262 bool slotCreatePlaylist(); 263 264 /** 265 * Open dialog to edit playlist. 266 * @param playlistPath path to playlist file 267 */ 268 void showPlaylistEditDialog(const QString& playlistPath); 269 270 /** 271 * Import. 272 */ 273 void slotImport(); 274 275 /** 276 * Tag import. 277 */ 278 void slotTagImport(); 279 280 /** 281 * Batch import. 282 */ 283 void slotBatchImport(); 284 285 /** 286 * Browse album cover artwork. 287 */ 288 void slotBrowseCoverArt(); 289 290 /** 291 * Export. 292 */ 293 void slotExport(); 294 295 /** 296 * Toggle auto hiding of tags. 297 */ 298 void slotSettingsAutoHideTags(); 299 300 /** 301 * Show or hide picture. 302 */ 303 void slotSettingsShowHidePicture(); 304 305 /** 306 * Find in tags of files. 307 */ find()308 void find() { findReplace(true); } 309 310 /** 311 * Find and replace in tags of files. 312 * @param findOnly true to display only find part of dialog 313 */ 314 void findReplace(bool findOnly = false); 315 316 /** 317 * Rename directory. 318 */ 319 void slotRenameDirectory(); 320 321 /** 322 * Number tracks. 323 */ 324 void slotNumberTracks(); 325 326 /** 327 * Filter. 328 */ 329 void slotFilter(); 330 331 /** 332 * Play audio file. 333 */ 334 void slotPlayAudio(); 335 336 /** 337 * Update files of current selection. 338 */ 339 void updateCurrentSelection(); 340 341 /** 342 * Apply selection change and update GUI controls. 343 * The new selection is stored and the GUI controls and frame list 344 * updated accordingly (filtered for multiple selection). 345 * @param selected selected items 346 * @param deselected deselected items 347 */ 348 void applySelectionChange(const QItemSelection& selected, 349 const QItemSelection& deselected); 350 351 /** 352 * Update GUI controls from the tags in the files. 353 * The new selection is stored and the GUI controls and frame list 354 * updated accordingly (filtered for multiple selection). 355 */ 356 void updateGuiControls(); 357 358 /** 359 * Rename the selected file(s). 360 */ 361 void renameFile(); 362 363 /** 364 * Delete the selected file(s). 365 */ 366 void deleteFile(); 367 368 /** 369 * Expand the file list. 370 */ 371 void expandFileList(); 372 373 signals: 374 /** 375 * Emitted when the dialog to add and edit a frame is closed. 376 * @param tagNr tag number 377 * @param frame edited frame if dialog was accepted, else 0 378 */ 379 void frameEdited(Frame::TagNumber tagNr, const Frame* frame); 380 381 /** 382 * Emitted when the dialog to select a frame is closed. 383 * @param tagNr tag number 384 * @param frame selected frame if dialog was accepted, else 0 385 */ 386 void frameSelected(Frame::TagNumber tagNr, const Frame* frame); 387 388 private slots: 389 /** 390 * Update ID3v2 tags in GUI controls from file displayed in frame list. 391 * 392 * @param taggedFile the selected file 393 * @param tagNr tag number 394 */ 395 void updateAfterFrameModification(TaggedFile* taggedFile, 396 Frame::TagNumber tagNr); 397 398 /** 399 * Show play tool bar. 400 */ 401 void showPlayToolBar(); 402 403 /** 404 * Expand item if it is a directory. 405 * 406 * @param index index of file in file proxy model 407 */ 408 void expandNextDirectory(const QPersistentModelIndex& index); 409 410 /** 411 * Show filter operation progress. 412 * @param type filter event type 413 * @param fileName name of file processed 414 * @param passed number of files which passed the filter 415 * @param total total number of files checked 416 */ 417 void filterProgress(int type, const QString& fileName, int passed, int total); 418 419 /** 420 * Set tagged files of directory from imported track data model. 421 */ 422 void applyImportedTrackData(); 423 424 /** 425 * Called when the edit frame dialog is finished. 426 * @param result dialog result 427 */ 428 void onEditFrameDialogFinished(int result); 429 430 /** 431 * Called when a playlist edit dialog is closed. 432 */ 433 void onPlaylistEditDialogFinished(); 434 435 /** 436 * Toggle expanded state of directory in the file list. 437 * @param index index of directory 438 */ 439 void toggleExpanded(const QModelIndex& index); 440 441 /** 442 * Deactivate showing of find replace results. 443 */ 444 void deactivateFindReplace(); 445 446 /** 447 * Ensure that found text is made visible in the GUI. 448 */ 449 void showFoundText(); 450 451 /** 452 * Update GUI controls after text has been replaced. 453 */ 454 void updateReplacedText(); 455 456 /** 457 * Show progress of long running operation in status bar. 458 * @param name name of operation 459 * @param done amount of work done 460 * @param total total amount of work 461 * @param abort if not 0, can be set to true to abort operation 462 */ 463 void showOperationProgress(const QString& name, int done, int total, 464 bool* abort); 465 466 /** 467 * Called when the item count of the file proxy model changed. 468 */ 469 void onItemCountChanged(); 470 471 /** 472 * Called when the item count of the file selection model changed. 473 */ 474 void onSelectionCountChanged(); 475 476 private: 477 /** 478 * Free allocated resources. 479 * Our destructor may not be called, so cleanup is done here. 480 */ 481 void cleanup(); 482 483 /** 484 * Save application options. 485 */ 486 void saveOptions(); 487 488 /** 489 * Load application options. 490 */ 491 void readOptions(); 492 493 /** 494 * Save all changed files. 495 * 496 * @param updateGui true to update GUI (controls, status, cursor) 497 */ 498 void saveDirectory(bool updateGui = false); 499 500 /** 501 * If anything was modified, save after asking user. 502 * 503 * @param doNotRevert if true, modifications are not reverted, this can be 504 * used to skip the possibly long process if the application is not be closed 505 * 506 * @return false if user canceled. 507 */ 508 bool saveModified(bool doNotRevert = false); 509 510 /** 511 * If a playlist was modified, save after asking user. 512 * @return false if user canceled. 513 */ 514 bool saveModifiedPlaylists(); 515 516 /** 517 * Update track data and create import dialog. 518 */ 519 void setupImportDialog(); 520 521 /** 522 * Write playlist according to playlist configuration. 523 * 524 * @param cfg playlist configuration to use 525 * 526 * @return true if ok. 527 */ 528 bool writePlaylist(const PlaylistConfig& cfg); 529 530 /** 531 * Terminate expanding the file list. 532 */ 533 void terminateExpandFileList(); 534 535 /** 536 * Terminate filtering the file list. 537 */ 538 void terminateFilter(); 539 540 /** 541 * Update GUI controls from the current selection. 542 */ 543 void updateGuiControlsFromSelection(); 544 545 /** 546 * Start monitoring the progress of a possibly long operation. 547 * 548 * If the operation takes longer than 3 seconds, a progress widget is shown. 549 * 550 * @param title title to be displayed in progress widget 551 * @param terminationHandler method to be called to terminate operation 552 * @param disconnectModel true to disconnect the file list models while the 553 * progress widget is shown 554 */ 555 void startProgressMonitoring(const QString& title, 556 void (BaseMainWindowImpl::*terminationHandler)(), 557 bool disconnectModel); 558 559 /** 560 * Stop monitoring the progress started with startProgressMonitoring(). 561 */ 562 void stopProgressMonitoring(); 563 564 /** 565 * Check progress of a possibly long operation. 566 * 567 * Progress monitoring is started with startProgressMonitoring(). This method 568 * will check if the opeation is running long enough to show a progress widget 569 * and update the progress information. It will call stopProgressMonitoring() 570 * when the operation is aborted. 571 * 572 * @param done amount of work done 573 * @param total total amount of work 574 * @param text text for progress label 575 */ 576 void checkProgressMonitoring(int done, int total, const QString& text); 577 578 /** 579 * Update label of status bar with information about the number of files. 580 */ 581 void updateStatusLabel(); 582 583 IPlatformTools* m_platformTools; 584 QMainWindow* m_w; 585 BaseMainWindow* m_self; 586 587 QTimer* m_deferredItemCountTimer; 588 QTimer* m_deferredSelectionCountTimer; 589 /** Label with normal status message */ 590 QLabel* m_statusLabel; 591 /** GUI with controls */ 592 Kid3Form* m_form; 593 /** Application logic */ 594 Kid3Application* m_app; 595 /** Import dialog */ 596 QScopedPointer<ImportDialog> m_importDialog; 597 /** Import from Tags dialog */ 598 QScopedPointer<TagImportDialog> m_tagImportDialog; 599 /** Batch import dialog */ 600 QScopedPointer<BatchImportDialog> m_batchImportDialog; 601 /** Browse cover art dialog */ 602 QScopedPointer<BrowseCoverArtDialog> m_browseCoverArtDialog; 603 /** Export dialog */ 604 ExportDialog* m_exportDialog; 605 /** Find and replace dialog */ 606 FindReplaceDialog* m_findReplaceDialog; 607 /** Rename directory dialog */ 608 QScopedPointer<RenDirDialog> m_renDirDialog; 609 /** Number tracks dialog */ 610 QScopedPointer<NumberTracksDialog> m_numberTracksDialog; 611 /** Filter dialog */ 612 QScopedPointer<FilterDialog> m_filterDialog; 613 /** Download dialog */ 614 DownloadDialog* m_downloadDialog; 615 /** Playlist dialog */ 616 QScopedPointer<PlaylistDialog> m_playlistDialog; 617 /** Playlist edit dialogs */ 618 QMap<QString, PlaylistEditDialog*> m_playlistEditDialogs; 619 /** Progress dialog */ 620 ProgressWidget* m_progressWidget; 621 QLabel* m_progressLabel; 622 QProgressBar* m_progressBar; 623 QToolButton* m_progressAbortButton; 624 /** Edit frame dialog */ 625 EditFrameFieldsDialog* m_editFrameDialog; 626 /** Play toolbar */ 627 PlayToolBar* m_playToolBar; 628 Frame m_editFrame; 629 TaggedFile* m_editFrameTaggedFile; 630 Frame::TagNumber m_editFrameTagNr; 631 QDateTime m_progressStartTime; 632 QString m_progressTitle; 633 void (BaseMainWindowImpl::*m_progressTerminationHandler)(); 634 int m_folderCount; 635 int m_fileCount; 636 int m_selectionCount; 637 bool m_progressDisconnected; 638 bool m_findReplaceActive; 639 bool m_expandNotificationNeeded; 640 }; 641 642 643 /** 644 * Base class for the main window. 645 * The main window classes for Qt (QMainWindow) and KDE (KXmlGuiWindow) 646 * have common functionality. The actual Kid3 main window can inherit from both 647 * the platform dependent main window class and this base class. Differences 648 * between the platforms can be handled by implementing the pure virtual methods 649 * of this class. Because this class cannot be a QObject (QMainWindow is 650 * already a QObject), most of its functionality is delegated to a QObject 651 * implementation class. 652 */ 653 class KID3_GUI_EXPORT BaseMainWindow { 654 public: 655 /** 656 * Constructor. 657 * 658 * @param mainWin main window 659 * @param platformTools platform specific tools 660 * @param app application context 661 */ 662 BaseMainWindow(QMainWindow* mainWin, IPlatformTools* platformTools, 663 Kid3Application *app); 664 665 /** 666 * Destructor. 667 */ 668 virtual ~BaseMainWindow(); 669 670 /** 671 * Init menu and toolbar actions. 672 */ 673 virtual void initActions() = 0; 674 675 /** 676 * Get keyboard shortcuts. 677 * @return mapping of action names to key sequences. 678 */ 679 virtual QMap<QString, QKeySequence> shortcutsMap() const = 0; 680 681 /** 682 * Add directory to recent files list. 683 * 684 * @param dirName path to directory 685 */ 686 virtual void addDirectoryToRecentFiles(const QString& dirName) = 0; 687 688 /** 689 * Read settings from the configuration. 690 */ 691 virtual void readConfig() = 0; 692 693 /** 694 * Store geometry and recent files in settings. 695 */ 696 virtual void saveConfig() = 0; 697 698 /** 699 * Get action for Settings/Auto Hide Tags. 700 * @return action. 701 */ 702 virtual QAction* autoHideTagsAction() = 0; 703 704 /** 705 * Get action for Settings/Hide Picture. 706 * @return action. 707 */ 708 virtual QAction* showHidePictureAction() = 0; 709 710 /** 711 * Set main window caption. 712 * 713 * @param caption caption without application name 714 * @param modified true if any file is modified 715 */ 716 virtual void setWindowCaption(const QString& caption, bool modified) = 0; 717 718 /** 719 * Play audio file. 720 */ 721 void slotPlayAudio(); 722 723 /** 724 * Update files of current selection. 725 */ 726 void updateCurrentSelection(); 727 728 /** 729 * Open directory, user has to confirm if current directory modified. 730 * 731 * @param paths directory or file paths 732 */ 733 void confirmedOpenDirectory(const QStringList& paths); 734 735 /** 736 * Access to implementation object. 737 * @return implementation object. 738 */ impl()739 BaseMainWindowImpl* impl() { return m_impl.data(); } 740 741 protected: 742 /** 743 * Initialize main window. 744 * Shall be called at end of constructor body in derived classes. 745 */ 746 void init(); 747 748 /** 749 * Change visibility of status bar. 750 * @param visible true to show status bar 751 */ 752 void setStatusBarVisible(bool visible); 753 754 /** 755 * Update modification state before closing. 756 * If anything was modified, save after asking user. 757 * Save options before closing. 758 * This method shall be called by closeEvent() (Qt) or 759 * queryClose() (KDE). 760 * 761 * @return false if user canceled, 762 * true will quit the application. 763 */ 764 bool queryBeforeClosing(); 765 766 /** 767 * Open recent directory. 768 * 769 * @param dir directory to open 770 */ 771 void openRecentDirectory(const QString& dir); 772 773 /** 774 * Set window title with information from directory, filter and modification 775 * state. 776 */ 777 void updateWindowCaption(); 778 779 /** 780 * Access to application. 781 * @return application. 782 */ 783 Kid3Application* app(); 784 785 /** 786 * Access to main form. 787 * @return main form. 788 */ 789 Kid3Form* form(); 790 791 private: 792 QScopedPointer<BaseMainWindowImpl> m_impl; 793 }; 794