File indexing completed on 2024-06-02 04:59:26

0001 /**
0002  * \file basemainwindow.h
0003  * Base class for main window.
0004  *
0005  * \b Project: Kid3
0006  * \author Urs Fleisch
0007  * \date 9 Jan 2003
0008  *
0009  * Copyright (C) 2003-2024  Urs Fleisch
0010  *
0011  * This file is part of Kid3.
0012  *
0013  * Kid3 is free software; you can redistribute it and/or modify
0014  * it under the terms of the GNU General Public License as published by
0015  * the Free Software Foundation; either version 2 of the License, or
0016  * (at your option) any later version.
0017  *
0018  * Kid3 is distributed in the hope that it will be useful,
0019  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0020  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0021  * GNU General Public License for more details.
0022  *
0023  * You should have received a copy of the GNU General Public License
0024  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
0025  */
0026 
0027 #pragma once
0028 
0029 #include <QMainWindow>
0030 #include <QDateTime>
0031 #include <QScopedPointer>
0032 #include "iframeeditor.h"
0033 #include "frame.h"
0034 #include "kid3api.h"
0035 
0036 class QLabel;
0037 class QProgressBar;
0038 class QToolButton;
0039 class QItemSelection;
0040 class QTimer;
0041 class ProgressWidget;
0042 class Kid3Form;
0043 class Kid3Application;
0044 class TaggedFile;
0045 class ImportDialog;
0046 class TagImportDialog;
0047 class BatchImportDialog;
0048 class ExportDialog;
0049 class FindReplaceDialog;
0050 class BrowseCoverArtDialog;
0051 class RenDirDialog;
0052 class NumberTracksDialog;
0053 class RenDirDialog;
0054 class FilterDialog;
0055 class FileFilter;
0056 class DownloadDialog;
0057 class PlaylistDialog;
0058 class PlaylistEditDialog;
0059 class PlaylistConfig;
0060 class EditFrameFieldsDialog;
0061 class PlayToolBar;
0062 class DirContents;
0063 class FileProxyModel;
0064 class DirProxyModel;
0065 class TrackDataModel;
0066 class IPlatformTools;
0067 class BaseMainWindow;
0068 
0069 /**
0070  * Implementation class for BaseMainWindow.
0071  * The reason for this implementation class is that a QObject is needed to
0072  * have slots. However, BaseMainWindow cannot inherit from QObject because it
0073  * is used with multiple inheritance together with another class which is a
0074  * QObject (actually a QMainWindow). Therefore the functionality of the main
0075  * put into this class which is then used as an implementation class by
0076  * BaseMainWindow.
0077  */
0078 class KID3_GUI_EXPORT BaseMainWindowImpl : public QObject, public IFrameEditor {
0079   Q_OBJECT
0080 public:
0081   /**
0082    * Constructor.
0083    *
0084    * @param mainWin main window widget
0085    * @param platformTools platform specific tools
0086    */
0087   BaseMainWindowImpl(QMainWindow* mainWin, IPlatformTools* platformTools, Kid3Application *app);
0088 
0089   /**
0090    * Destructor.
0091    */
0092   ~BaseMainWindowImpl() override;
0093 
0094   /**
0095    * Create dialog to edit a frame and update the fields
0096    * if Ok is returned.
0097    * frameEdited() is emitted when the edit dialog is closed with the edited
0098    * frame as a parameter if it was accepted.
0099    *
0100    * @param frame frame to edit
0101    * @param taggedFile tagged file where frame has to be set
0102    */
0103   void editFrameOfTaggedFile(const Frame* frame, TaggedFile* taggedFile) override;
0104 
0105   /**
0106    * Let user select a frame type.
0107    * frameSelected() is emitted when the edit dialog is closed with the selected
0108    * frame as a parameter if a frame is selected.
0109    *
0110    * @param frame is filled with the selected frame
0111    * @param taggedFile tagged file for which frame has to be selected
0112    */
0113   void selectFrame(Frame* frame, const TaggedFile* taggedFile) override;
0114 
0115   /**
0116    * Return object which emits frameSelected(), frameEdited() signals.
0117    *
0118    * @return object which emits signals.
0119    */
0120   QObject* qobject() override;
0121 
0122   /**
0123    * Get the tag number of the edited frame.
0124    * @return tag number.
0125    */
0126   Frame::TagNumber tagNumber() const override;
0127 
0128   /**
0129    * Set the tag number of the edited frame.
0130    * @param tagNr tag number
0131    */
0132   void setTagNumber(Frame::TagNumber tagNr) override;
0133 
0134   /**
0135    * Set back pointer for implementation class.
0136    *
0137    * @param self back pointer
0138    */
0139   void setBackPointer(BaseMainWindow* self) { m_self = self; }
0140 
0141   /**
0142    * Initialize main window.
0143    * Shall be called at end of constructor body.
0144    */
0145   void init();
0146 
0147   /**
0148    * Change visibility of status bar.
0149    * @param visible true to show status bar
0150    */
0151   void setStatusBarVisible(bool visible);
0152 
0153   /**
0154    * Update modification state before closing.
0155    * If anything was modified, save after asking user.
0156    * Save options before closing.
0157    * This method shall be called by closeEvent() (Qt) or
0158    * queryClose() (KDE).
0159    *
0160    * @return false if user canceled,
0161    *         true will quit the application.
0162    */
0163   bool queryBeforeClosing();
0164 
0165   /**
0166    * Open recent directory.
0167    *
0168    * @param dir directory to open
0169    */
0170   void openRecentDirectory(const QString& dir);
0171 
0172   /**
0173    * Apply configuration changes.
0174    */
0175   void applyChangedConfiguration();
0176 
0177   /**
0178    * Apply keyboard shortcut changes.
0179    */
0180   void applyChangedShortcuts();
0181 
0182   /**
0183    * Get media player actions.
0184    * @return list with named actions for "audio_play", "audio_stop",
0185    * "audio_previous", "audio_next".
0186    */
0187   QList<QAction*> mediaActions() const;
0188 
0189   /**
0190    * Access to application.
0191    * @return application.
0192    */
0193   Kid3Application* app() { return m_app; }
0194 
0195   /**
0196    * Access to main form.
0197    * @return main form.
0198    */
0199   Kid3Form* form() { return m_form; }
0200 
0201 public slots:
0202   /**
0203    * Set window title with information from directory, filter and modification
0204    * state.
0205    */
0206   void updateWindowCaption();
0207 
0208   /**
0209    * Open directory, user has to confirm if current directory modified.
0210    *
0211    * @param paths directory or file paths
0212    */
0213   void confirmedOpenDirectory(const QStringList& paths);
0214 
0215   /**
0216    * Update the recent file list and the caption when a new directory
0217    * is opened.
0218    */
0219   void onDirectoryOpened();
0220 
0221   /**
0222    * Request new directory and open it.
0223    */
0224   void slotFileOpen();
0225 
0226   /**
0227    * Request new directory and open it.
0228    */
0229   void slotFileOpenDirectory();
0230 
0231   /**
0232    * Reload the current directory.
0233    */
0234   void slotFileReload();
0235 
0236   /**
0237    * Save modified files.
0238    */
0239   void slotFileSave();
0240 
0241   /**
0242    * Quit application.
0243    */
0244   void slotFileQuit();
0245 
0246   /**
0247    * Change status message.
0248    *
0249    * @param text message
0250    */
0251   void slotStatusMsg(const QString& text);
0252 
0253   /**
0254    * Clear status message.
0255    * To be called when a message set with slotStatusMsg() is no longer valid.
0256    */
0257   void slotClearStatusMsg();
0258 
0259   /**
0260    * Show playlist dialog.
0261    */
0262   void slotPlaylistDialog();
0263 
0264   /**
0265    * Create playlist.
0266    *
0267    * @return true if ok.
0268    */
0269   bool slotCreatePlaylist();
0270 
0271   /**
0272    * Open dialog to edit playlist.
0273    * @param playlistPath path to playlist file
0274    */
0275   void showPlaylistEditDialog(const QString& playlistPath);
0276 
0277   /**
0278    * Import.
0279    */
0280   void slotImport();
0281 
0282   /**
0283    * Tag import.
0284    */
0285   void slotTagImport();
0286 
0287   /**
0288    * Batch import.
0289    */
0290   void slotBatchImport();
0291 
0292   /**
0293    * Browse album cover artwork.
0294    */
0295   void slotBrowseCoverArt();
0296 
0297   /**
0298    * Export.
0299    */
0300   void slotExport();
0301 
0302   /**
0303    * Toggle auto hiding of tags.
0304    */
0305   void slotSettingsAutoHideTags();
0306 
0307   /**
0308    * Show or hide picture.
0309    */
0310   void slotSettingsShowHidePicture();
0311 
0312   /**
0313    * Find in tags of files.
0314    */
0315   void find() { findReplace(true); }
0316 
0317   /**
0318    * Find and replace in tags of files.
0319    * @param findOnly true to display only find part of dialog
0320    */
0321   void findReplace(bool findOnly = false);
0322 
0323   /**
0324    * Rename directory.
0325    */
0326   void slotRenameDirectory();
0327 
0328   /**
0329    * Number tracks.
0330    */
0331   void slotNumberTracks();
0332 
0333   /**
0334    * Filter.
0335    */
0336   void slotFilter();
0337 
0338   /**
0339    * Play audio file.
0340    */
0341   void slotPlayAudio();
0342 
0343   /**
0344    * Update files of current selection.
0345    */
0346   void updateCurrentSelection();
0347 
0348   /**
0349    * Apply selection change and update GUI controls.
0350    * The new selection is stored and the GUI controls and frame list
0351    * updated accordingly (filtered for multiple selection).
0352    * @param selected selected items
0353    * @param deselected deselected items
0354    */
0355   void applySelectionChange(const QItemSelection& selected,
0356                             const QItemSelection& deselected);
0357 
0358   /**
0359    * Update GUI controls from the tags in the files.
0360    * The new selection is stored and the GUI controls and frame list
0361    * updated accordingly (filtered for multiple selection).
0362    */
0363   void updateGuiControls();
0364 
0365   /**
0366    * Rename the selected file(s).
0367    */
0368   void renameFile();
0369 
0370   /**
0371    * Delete the selected file(s).
0372    */
0373   void deleteFile();
0374 
0375   /**
0376    * Expand the file list.
0377    */
0378   void expandFileList();
0379 
0380 signals:
0381   /**
0382    * Emitted when the dialog to add and edit a frame is closed.
0383    * @param tagNr tag number
0384    * @param frame edited frame if dialog was accepted, else 0
0385    */
0386   void frameEdited(Frame::TagNumber tagNr, const Frame* frame);
0387 
0388   /**
0389    * Emitted when the dialog to select a frame is closed.
0390    * @param tagNr tag number
0391    * @param frame selected frame if dialog was accepted, else 0
0392    */
0393   void frameSelected(Frame::TagNumber tagNr, const Frame* frame);
0394 
0395 private slots:
0396   /**
0397    * Update ID3v2 tags in GUI controls from file displayed in frame list.
0398    *
0399    * @param taggedFile the selected file
0400    * @param tagNr tag number
0401    */
0402   void updateAfterFrameModification(TaggedFile* taggedFile,
0403                                     Frame::TagNumber tagNr);
0404 
0405   /**
0406    * Show play tool bar.
0407    */
0408   void showPlayToolBar();
0409 
0410   /**
0411    * Expand item if it is a directory.
0412    *
0413    * @param index index of file in file proxy model
0414    */
0415   void expandNextDirectory(const QPersistentModelIndex& index);
0416 
0417   /**
0418    * Show filter operation progress.
0419    * @param type filter event type
0420    * @param fileName name of file processed
0421    * @param passed number of files which passed the filter
0422    * @param total total number of files checked
0423    */
0424   void filterProgress(int type, const QString& fileName, int passed, int total);
0425 
0426   /**
0427    * Set tagged files of directory from imported track data model.
0428    */
0429   void applyImportedTrackData();
0430 
0431   /**
0432    * Called when the edit frame dialog is finished.
0433    * @param result dialog result
0434    */
0435   void onEditFrameDialogFinished(int result);
0436 
0437   /**
0438    * Called when a playlist edit dialog is closed.
0439    */
0440   void onPlaylistEditDialogFinished();
0441 
0442   /**
0443    * Toggle expanded state of directory in the file list.
0444    * @param index index of directory
0445    */
0446   void toggleExpanded(const QModelIndex& index);
0447 
0448   /**
0449    * Deactivate showing of find replace results.
0450    */
0451   void deactivateFindReplace();
0452 
0453   /**
0454    * Ensure that found text is made visible in the GUI.
0455    */
0456   void showFoundText();
0457 
0458   /**
0459    * Update GUI controls after text has been replaced.
0460    */
0461   void updateReplacedText();
0462 
0463   /**
0464    * Show progress of long running operation in status bar.
0465    * @param name name of operation
0466    * @param done amount of work done
0467    * @param total total amount of work
0468    * @param abort if not 0, can be set to true to abort operation
0469    */
0470   void showOperationProgress(const QString& name, int done, int total,
0471                              bool* abort);
0472 
0473   /**
0474    * Called when the item count of the file proxy model changed.
0475    */
0476   void onItemCountChanged();
0477 
0478   /**
0479    * Called when the item count of the file selection model changed.
0480    */
0481   void onSelectionCountChanged();
0482 
0483 private:
0484   /**
0485    * Free allocated resources.
0486    * Our destructor may not be called, so cleanup is done here.
0487    */
0488   void cleanup();
0489 
0490   /**
0491    * Save application options.
0492    */
0493   void saveOptions();
0494 
0495   /**
0496    * Load application options.
0497    */
0498   void readOptions();
0499 
0500   /**
0501    * Save state of play tool bar.
0502    */
0503   void savePlayToolBarConfig();
0504 
0505   /**
0506    * Restore state of play tool bar.
0507    */
0508   void readPlayToolBarConfig();
0509 
0510 
0511   /**
0512    * Save all changed files.
0513    *
0514    * @param updateGui true to update GUI (controls, status, cursor)
0515    */
0516   void saveDirectory(bool updateGui = false);
0517 
0518   /**
0519    * If anything was modified, save after asking user.
0520    *
0521    * @param doNotRevert if true, modifications are not reverted, this can be
0522    * used to skip the possibly long process if the application is not be closed
0523    *
0524    * @return false if user canceled.
0525    */
0526   bool saveModified(bool doNotRevert = false);
0527 
0528   /**
0529    * If a playlist was modified, save after asking user.
0530    * @return false if user canceled.
0531    */
0532   bool saveModifiedPlaylists();
0533 
0534   /**
0535    * Update track data and create import dialog.
0536    */
0537   void setupImportDialog();
0538 
0539   /**
0540    * Write playlist according to playlist configuration.
0541    *
0542    * @param cfg playlist configuration to use
0543    *
0544    * @return true if ok.
0545    */
0546   bool writePlaylist(const PlaylistConfig& cfg);
0547 
0548   /**
0549    * Terminate expanding the file list.
0550    */
0551   void terminateExpandFileList();
0552 
0553   /**
0554    * Terminate filtering the file list.
0555    */
0556   void terminateFilter();
0557 
0558   /**
0559    * Update GUI controls from the current selection.
0560    */
0561   void updateGuiControlsFromSelection();
0562 
0563   /**
0564    * Start monitoring the progress of a possibly long operation.
0565    *
0566    * If the operation takes longer than 3 seconds, a progress widget is shown.
0567    *
0568    * @param title title to be displayed in progress widget
0569    * @param terminationHandler method to be called to terminate operation
0570    * @param disconnectModel true to disconnect the file list models while the
0571    * progress widget is shown
0572    */
0573   void startProgressMonitoring(const QString& title,
0574                                void (BaseMainWindowImpl::*terminationHandler)(),
0575                                bool disconnectModel);
0576 
0577   /**
0578    * Stop monitoring the progress started with startProgressMonitoring().
0579    */
0580   void stopProgressMonitoring();
0581 
0582   /**
0583    * Check progress of a possibly long operation.
0584    *
0585    * Progress monitoring is started with startProgressMonitoring(). This method
0586    * will check if the opeation is running long enough to show a progress widget
0587    * and update the progress information. It will call stopProgressMonitoring()
0588    * when the operation is aborted.
0589    *
0590    * @param done amount of work done
0591    * @param total total amount of work
0592    * @param text text for progress label
0593    */
0594   void checkProgressMonitoring(int done, int total, const QString& text);
0595 
0596   /**
0597    * Update label of status bar with information about the number of files.
0598    */
0599   void updateStatusLabel();
0600 
0601   IPlatformTools* m_platformTools;
0602   QMainWindow* m_w;
0603   BaseMainWindow* m_self;
0604 
0605   QTimer* m_deferredItemCountTimer;
0606   QTimer* m_deferredSelectionCountTimer;
0607   /** Label with normal status message */
0608   QLabel* m_statusLabel;
0609   /** GUI with controls */
0610   Kid3Form* m_form;
0611   /** Application logic */
0612   Kid3Application* m_app;
0613   /** Import dialog */
0614   QScopedPointer<ImportDialog> m_importDialog;
0615   /** Import from Tags dialog */
0616   QScopedPointer<TagImportDialog> m_tagImportDialog;
0617   /** Batch import dialog */
0618   QScopedPointer<BatchImportDialog> m_batchImportDialog;
0619   /** Browse cover art dialog */
0620   QScopedPointer<BrowseCoverArtDialog> m_browseCoverArtDialog;
0621   /** Export dialog */
0622   ExportDialog* m_exportDialog;
0623   /** Find and replace dialog */
0624   FindReplaceDialog* m_findReplaceDialog;
0625   /** Rename directory dialog */
0626   QScopedPointer<RenDirDialog> m_renDirDialog;
0627   /** Number tracks dialog */
0628   QScopedPointer<NumberTracksDialog> m_numberTracksDialog;
0629   /** Filter dialog */
0630   QScopedPointer<FilterDialog> m_filterDialog;
0631   /** Download dialog */
0632   DownloadDialog* m_downloadDialog;
0633   /** Playlist dialog */
0634   QScopedPointer<PlaylistDialog> m_playlistDialog;
0635   /** Playlist edit dialogs */
0636   QMap<QString, PlaylistEditDialog*> m_playlistEditDialogs;
0637   /** Progress dialog */
0638   ProgressWidget* m_progressWidget;
0639   QLabel* m_progressLabel;
0640   QProgressBar* m_progressBar;
0641   QToolButton* m_progressAbortButton;
0642   /** Edit frame dialog */
0643   EditFrameFieldsDialog* m_editFrameDialog;
0644   /** Play toolbar */
0645   PlayToolBar* m_playToolBar;
0646   Frame m_editFrame;
0647   TaggedFile* m_editFrameTaggedFile;
0648   Frame::TagNumber m_editFrameTagNr;
0649   QDateTime m_progressStartTime;
0650   QString m_progressTitle;
0651   void (BaseMainWindowImpl::*m_progressTerminationHandler)();
0652   int m_folderCount;
0653   int m_fileCount;
0654   int m_selectionCount;
0655   bool m_progressDisconnected;
0656   bool m_findReplaceActive;
0657   bool m_expandNotificationNeeded;
0658 };
0659 
0660 
0661 /**
0662  * Base class for the main window.
0663  * The main window classes for Qt (QMainWindow) and KDE (KXmlGuiWindow)
0664  * have common functionality. The actual Kid3 main window can inherit from both
0665  * the platform dependent main window class and this base class. Differences
0666  * between the platforms can be handled by implementing the pure virtual methods
0667  * of this class. Because this class cannot be a QObject (QMainWindow is
0668  * already a QObject), most of its functionality is delegated to a QObject
0669  * implementation class.
0670  */
0671 class KID3_GUI_EXPORT BaseMainWindow {
0672 public:
0673   /**
0674    * Constructor.
0675    *
0676    * @param mainWin main window
0677    * @param platformTools platform specific tools
0678    * @param app application context
0679    */
0680   BaseMainWindow(QMainWindow* mainWin, IPlatformTools* platformTools,
0681                  Kid3Application *app);
0682 
0683   /**
0684    * Destructor.
0685    */
0686   virtual ~BaseMainWindow();
0687 
0688   /**
0689    * Init menu and toolbar actions.
0690    */
0691   virtual void initActions() = 0;
0692 
0693   /**
0694    * Get keyboard shortcuts.
0695    * @return mapping of action names to key sequences.
0696    */
0697   virtual QMap<QString, QKeySequence> shortcutsMap() const = 0;
0698 
0699   /**
0700    * Add directory to recent files list.
0701    *
0702    * @param dirName path to directory
0703    */
0704   virtual void addDirectoryToRecentFiles(const QString& dirName) = 0;
0705 
0706   /**
0707    * Read settings from the configuration.
0708    */
0709   virtual void readConfig() = 0;
0710 
0711   /**
0712    * Store geometry and recent files in settings.
0713    */
0714   virtual void saveConfig() = 0;
0715 
0716   /**
0717    * Get action for Settings/Auto Hide Tags.
0718    * @return action.
0719    */
0720   virtual QAction* autoHideTagsAction() = 0;
0721 
0722   /**
0723    * Get action for Settings/Hide Picture.
0724    * @return action.
0725    */
0726   virtual QAction* showHidePictureAction() = 0;
0727 
0728   /**
0729    * Set main window caption.
0730    *
0731    * @param caption caption without application name
0732    * @param modified true if any file is modified
0733    */
0734   virtual void setWindowCaption(const QString& caption, bool modified) = 0;
0735 
0736   /**
0737    * Play audio file.
0738    */
0739   void slotPlayAudio();
0740 
0741   /**
0742    * Update files of current selection.
0743    */
0744   void updateCurrentSelection();
0745 
0746   /**
0747    * Open directory, user has to confirm if current directory modified.
0748    *
0749    * @param paths directory or file paths
0750    */
0751   void confirmedOpenDirectory(const QStringList& paths);
0752 
0753   /**
0754    * Access to implementation object.
0755    * @return implementation object.
0756    */
0757   BaseMainWindowImpl* impl() { return m_impl.data(); }
0758 
0759 protected:
0760   /**
0761    * Initialize main window.
0762    * Shall be called at end of constructor body in derived classes.
0763    */
0764   void init();
0765 
0766   /**
0767    * Change visibility of status bar.
0768    * @param visible true to show status bar
0769    */
0770   void setStatusBarVisible(bool visible);
0771 
0772   /**
0773    * Update modification state before closing.
0774    * If anything was modified, save after asking user.
0775    * Save options before closing.
0776    * This method shall be called by closeEvent() (Qt) or
0777    * queryClose() (KDE).
0778    *
0779    * @return false if user canceled,
0780    *         true will quit the application.
0781    */
0782   bool queryBeforeClosing();
0783 
0784   /**
0785    * Open recent directory.
0786    *
0787    * @param dir directory to open
0788    */
0789   void openRecentDirectory(const QString& dir);
0790 
0791   /**
0792    * Set window title with information from directory, filter and modification
0793    * state.
0794    */
0795   void updateWindowCaption();
0796 
0797   /**
0798    * Access to application.
0799    * @return application.
0800    */
0801   Kid3Application* app();
0802 
0803   /**
0804    * Access to main form.
0805    * @return main form.
0806    */
0807   Kid3Form* form();
0808 
0809 private:
0810   QScopedPointer<BaseMainWindowImpl> m_impl;
0811 };