File indexing completed on 2024-04-21 04:50:08

0001 /*
0002     SPDX-FileCopyrightText: 1998-2009 Sebastian Trueg <trueg@k3b.org>
0003     SPDX-FileCopyrightText: 2009-2011 Michal Malek <michalm@jabster.pl>
0004     SPDX-FileCopyrightText: 1998-2009 Sebastian Trueg <trueg@k3b.org>
0005 
0006     SPDX-License-Identifier: GPL-2.0-or-later
0007 */
0008 
0009 #include "k3b.h"
0010 #include "k3bappdevicemanager.h"
0011 #include "k3bapplication.h"
0012 #include "k3baudiodecoder.h"
0013 #include "k3baudiodoc.h"
0014 #include "k3baudiotrackdialog.h"
0015 #include "k3baudioview.h"
0016 #include "k3bcuefileparser.h"
0017 #include "k3bdatadoc.h"
0018 #include "k3bdataview.h"
0019 #include "k3bdeviceselectiondialog.h"
0020 #include "k3bdirview.h"
0021 #include "k3bexternalbinmanager.h"
0022 #include "k3bfiletreeview.h"
0023 #include "k3bglobals.h"
0024 #include "k3binterface.h"
0025 #include "k3biso9660.h"
0026 #include "k3bjob.h"
0027 #include "k3bmediacache.h"
0028 #include "k3bmediaselectiondialog.h"
0029 #include "k3bmedium.h"
0030 #include "k3bmixeddoc.h"
0031 #include "k3bmixedview.h"
0032 #include "k3bmovixdoc.h"
0033 #include "k3bmovixview.h"
0034 #include "k3bprojectburndialog.h"
0035 #include "k3bplugin.h"
0036 #include "k3bpluginmanager.h"
0037 #include "k3bprojectmanager.h"
0038 #include "k3bprojecttabwidget.h"
0039 #include "k3bsignalwaiter.h"
0040 #include "k3bstdguiitems.h"
0041 #include "k3bsystemproblemdialog.h"
0042 #include "k3bstatusbarmanager.h"
0043 #include "k3btempdirselectionwidget.h"
0044 #include "k3bthemedheader.h"
0045 #include "k3bthememanager.h"
0046 #include "k3burlnavigator.h"
0047 #include "k3bvcddoc.h"
0048 #include "k3bvcdview.h"
0049 #include "k3bvideodvddoc.h"
0050 #include "k3bvideodvdview.h"
0051 #include "k3bview.h"
0052 #include "k3bwelcomewidget.h"
0053 #include "misc/k3bimagewritingdialog.h"
0054 #include "misc/k3bmediacopydialog.h"
0055 #include "misc/k3bmediaformattingdialog.h"
0056 #include "option/k3boptiondialog.h"
0057 #include "projects/k3bdatamultisessionimportdialog.h"
0058 
0059 #include <KConfig>
0060 #include <KSharedConfig>
0061 #include <KRecentFilesAction>
0062 #include <KStandardAction>
0063 #include <KAboutData>
0064 #include <KProcess>
0065 #include <KLocalizedString>
0066 #include <KIO/DeleteJob>
0067 #include <KIO/StatJob>
0068 #include <KRecentDocument>
0069 #include <KFilePlacesModel>
0070 #include <KActionMenu>
0071 #include <KMessageBox>
0072 #include <KToggleAction>
0073 #include <KActionCollection>
0074 #include <KEditToolBar>
0075 #include <KXMLGUIFactory>
0076 #include <KShortcutsDialog>
0077 
0078 #include <QtAlgorithms>
0079 #include <QDir>
0080 #include <QFile>
0081 #include <QFileInfo>
0082 #include <QList>
0083 #include <QMimeDatabase>
0084 #include <QMimeType>
0085 #include <QStandardPaths>
0086 #include <QString>
0087 #include <QTimer>
0088 #include <QUrl>
0089 #include <QAction>
0090 #include <QFileDialog>
0091 #include <QGridLayout>
0092 #include <QLayout>
0093 #include <QMenuBar>
0094 #include <QSplitter>
0095 #include <QStackedWidget>
0096 #include <QStatusBar>
0097 
0098 #include <cstdlib>
0099 
0100 
0101 namespace {
0102 
0103     bool isProjectFile( QMimeDatabase const& mimeDatabase, QUrl const& url )
0104     {
0105         return mimeDatabase.mimeTypeForUrl( url ).inherits( "application/x-k3b" );
0106     }
0107 
0108 
0109     bool isDiscImage( const QUrl& url )
0110     {
0111         K3b::Iso9660 iso( url.toLocalFile() );
0112         if( iso.open() ) {
0113             iso.close();
0114             return true;
0115         }
0116 
0117         K3b::CueFileParser parser( url.toLocalFile() );
0118         if( parser.isValid() &&
0119             (parser.toc().contentType() == K3b::Device::DATA || parser.toc().contentType() == K3b::Device::MIXED) ) {
0120             return true;
0121         }
0122 
0123         return false;
0124     }
0125 
0126 
0127     bool areAudioFiles( const QList<QUrl>& urls )
0128     {
0129         // check if the files are all audio we can handle. If so create an audio project
0130         bool audio = true;
0131         QList<K3b::Plugin*> fl = k3bcore->pluginManager()->plugins( "AudioDecoder" );
0132         for( QList<QUrl>::const_iterator it = urls.begin(); it != urls.end(); ++it ) {
0133             const QUrl& url = *it;
0134 
0135             if( QFileInfo(url.toLocalFile()).isDir() ) {
0136                 audio = false;
0137                 break;
0138             }
0139 
0140             bool a = false;
0141             Q_FOREACH( K3b::Plugin* plugin, fl ) {
0142                 if( static_cast<K3b::AudioDecoderFactory*>( plugin )->canDecode( url ) ) {
0143                     a = true;
0144                     break;
0145                 }
0146             }
0147             if( !a ) {
0148                 audio = a;
0149                 break;
0150             }
0151         }
0152 
0153         if( !audio && urls.count() == 1 ) {
0154             // see if it's an audio cue file
0155             K3b::CueFileParser parser( urls.first().toLocalFile() );
0156             if( parser.isValid() && parser.toc().contentType() == K3b::Device::AUDIO ) {
0157                 audio = true;
0158             }
0159         }
0160         return audio;
0161     }
0162     
0163     void setEqualSizes( QSplitter* splitter )
0164     {
0165         QList<int> sizes = splitter->sizes();
0166         int sum = 0;
0167         for( int i = 0; i < sizes.count(); ++i )
0168         {
0169             sum += sizes.at( i );
0170         }
0171 
0172         std::fill( sizes.begin(), sizes.end(), sum / sizes.count() );
0173         splitter->setSizes( sizes );
0174     }
0175 
0176 } // namespace
0177 
0178 
0179 class K3b::MainWindow::Private
0180 {
0181 public:
0182     KRecentFilesAction* actionFileOpenRecent;
0183     QAction* actionFileSave;
0184     QAction* actionFileSaveAs;
0185     QAction* actionFileClose;
0186     KToggleAction* actionViewStatusBar;
0187     KToggleAction* actionViewDocumentHeader;
0188 
0189     /** The MDI-Interface is managed by this tabbed view */
0190     ProjectTabWidget* documentTab;
0191 
0192     // project actions
0193     QList<QAction*> dataProjectActions;
0194 
0195     // The K3b-specific widgets
0196     DirView* dirView;
0197     OptionDialog* optionDialog;
0198 
0199     StatusBarManager* statusBarManager;
0200 
0201     bool initialized;
0202 
0203     // the funny header
0204     ThemedHeader* documentHeader;
0205 
0206     KFilePlacesModel* filePlacesModel;
0207     K3b::UrlNavigator* urlNavigator;
0208 
0209     K3b::Doc* lastDoc;
0210 
0211     QSplitter* mainSplitter;
0212     K3b::WelcomeWidget* welcomeWidget;
0213     QStackedWidget* documentStack;
0214     QWidget* documentHull;
0215 
0216     QMimeDatabase mimeDatabase;
0217 };
0218 
0219 K3b::MainWindow::MainWindow()
0220     : KXmlGuiWindow(0),
0221       d( new Private )
0222 {
0223     d->lastDoc = 0;
0224 
0225     setPlainCaption( i18n("K3b - The CD and DVD Kreator") );
0226 
0227     // /////////////////////////////////////////////////////////////////
0228     // call inits to invoke all other construction parts
0229     initActions();
0230     initView();
0231     initStatusBar();
0232     createGUI();
0233 
0234     // /////////////////////////////////////////////////////////////////
0235     // incorporate Device Manager into main window
0236     factory()->addClient( k3bappcore->appDeviceManager() );
0237     connect( k3bappcore->appDeviceManager(), SIGNAL(detectingDiskInfo(K3b::Device::Device*)),
0238              this, SLOT(showDiskInfo(K3b::Device::Device*)) );
0239 
0240     // we need the actions for the welcomewidget
0241     KConfigGroup grp( config(), QStringLiteral("Welcome Widget") );
0242     d->welcomeWidget->loadConfig( grp );
0243 
0244     // fill the tabs action menu
0245     d->documentTab->addAction( d->actionFileSave );
0246     d->documentTab->addAction( d->actionFileSaveAs );
0247     d->documentTab->addAction( d->actionFileClose );
0248 
0249     // /////////////////////////////////////////////////////////////////
0250     // disable actions at startup
0251     slotStateChanged( "state_project_active", KXMLGUIClient::StateReverse );
0252 
0253     connect( k3bappcore->projectManager(), SIGNAL(newProject(K3b::Doc*)), this, SLOT(createClient(K3b::Doc*)) );
0254     connect( k3bcore->deviceManager(), SIGNAL(changed()), this, SLOT(slotCheckSystemTimed()) );
0255 
0256     // FIXME: now make sure the welcome screen is displayed completely
0257     //resize( 780, 550 );
0258 //   getMainDockWidget()->resize( getMainDockWidget()->size().expandedTo( d->welcomeWidget->sizeHint() ) );
0259 //   d->dirTreeDock->resize( QSize( d->dirTreeDock->sizeHint().width(), d->dirTreeDock->height() ) );
0260 
0261     readOptions();
0262 
0263     new Interface( this );
0264 }
0265 
0266 K3b::MainWindow::~MainWindow()
0267 {
0268     delete d;
0269 }
0270 
0271 
0272 KSharedConfig::Ptr K3b::MainWindow::config() const
0273 {
0274     return KSharedConfig::openConfig();
0275 }
0276 
0277 
0278 void K3b::MainWindow::initActions()
0279 {
0280     // merge in the device actions from the device manager
0281     // operator+= is deprecated but I know no other way to do this. Why does the KDE app framework
0282     // need to have all actions in the mainwindow's actioncollection anyway (or am I just to stupid to
0283     // see the correct solution?)
0284 
0285     // clang-analyzer wrongly treat KF5's KStandardAction::open as Unix API Improper use of 'open'
0286     QAction* actionFileOpen = KStandardAction::open( this, SLOT(slotFileOpen()), actionCollection() );
0287     actionFileOpen->setToolTip( i18n( "Opens an existing project" ) );
0288     actionFileOpen->setStatusTip( actionFileOpen->toolTip() );
0289 
0290     d->actionFileOpenRecent = KStandardAction::openRecent( this, SLOT(slotFileOpenRecent(QUrl)), actionCollection() );
0291     d->actionFileOpenRecent->setToolTip( i18n( "Opens a recently used file" ) );
0292     d->actionFileOpenRecent->setStatusTip( d->actionFileOpenRecent->toolTip() );
0293 
0294     d->actionFileSave = KStandardAction::save( this, SLOT(slotFileSave()), actionCollection() );
0295     d->actionFileSave->setToolTip( i18n( "Saves the current project" ) );
0296     d->actionFileSave->setStatusTip( d->actionFileSave->toolTip() );
0297 
0298     d->actionFileSaveAs = KStandardAction::saveAs( this, SLOT(slotFileSaveAs()), actionCollection() );
0299     d->actionFileSaveAs->setToolTip( i18n( "Saves the current project to a new URL" ) );
0300     d->actionFileSaveAs->setStatusTip( d->actionFileSaveAs->toolTip() );
0301 
0302     QAction* actionFileSaveAll = new QAction( QIcon::fromTheme( "document-save-all" ), i18n("Save All"), this );
0303     actionFileSaveAll->setToolTip( i18n( "Saves all open projects" ) );
0304     actionFileSaveAll->setStatusTip( actionFileSaveAll->toolTip() );
0305     actionCollection()->addAction( "file_save_all", actionFileSaveAll );
0306     connect( actionFileSaveAll, SIGNAL(triggered(bool)), this, SLOT(slotFileSaveAll()) );
0307 
0308     d->actionFileClose = KStandardAction::close( this, SLOT(slotFileClose()), actionCollection() );
0309     d->actionFileClose->setToolTip(i18n("Closes the current project"));
0310     d->actionFileClose->setStatusTip( d->actionFileClose->toolTip() );
0311 
0312     QAction* actionFileCloseAll = new QAction( i18n("Close All"), this );
0313     actionFileCloseAll->setToolTip(i18n("Closes all open projects"));
0314     actionFileCloseAll->setStatusTip( actionFileCloseAll->toolTip() );
0315     actionCollection()->addAction( "file_close_all", actionFileCloseAll );
0316     connect( actionFileCloseAll, SIGNAL(triggered(bool)), this, SLOT(slotFileCloseAll()) );
0317 
0318     QAction* actionFileQuit = KStandardAction::quit(this, SLOT(slotFileQuit()), actionCollection());
0319     actionFileQuit->setToolTip(i18n("Quits the application"));
0320     actionFileQuit->setStatusTip( actionFileQuit->toolTip() );
0321 
0322     QAction* actionFileNewAudio = new QAction( QIcon::fromTheme( "media-optical-audio" ), i18n("New &Audio CD Project"), this );
0323     actionFileNewAudio->setToolTip( i18n("Creates a new audio CD project") );
0324     actionFileNewAudio->setStatusTip( actionFileNewAudio->toolTip() );
0325     actionCollection()->addAction( "file_new_audio", actionFileNewAudio );
0326     connect( actionFileNewAudio, SIGNAL(triggered(bool)), this, SLOT(slotNewAudioDoc()) );
0327 
0328     QAction* actionFileNewData = new QAction( QIcon::fromTheme( "media-optical-data" ), i18n("New &Data Project"), this );
0329     actionFileNewData->setToolTip( i18n("Creates a new data project") );
0330     actionFileNewData->setStatusTip( actionFileNewData->toolTip() );
0331     actionCollection()->addAction( "file_new_data", actionFileNewData );
0332     connect( actionFileNewData, SIGNAL(triggered(bool)), this, SLOT(slotNewDataDoc()) );
0333 
0334     QAction* actionFileNewMixed = new QAction( QIcon::fromTheme( "media-optical-mixed-cd" ), i18n("New &Mixed Mode CD Project"), this );
0335     actionFileNewMixed->setToolTip( i18n("Creates a new mixed audio/data CD project") );
0336     actionFileNewMixed->setStatusTip( actionFileNewMixed->toolTip() );
0337     actionCollection()->addAction( "file_new_mixed", actionFileNewMixed );
0338     connect( actionFileNewMixed, SIGNAL(triggered(bool)), this, SLOT(slotNewMixedDoc()) );
0339 
0340     QAction* actionFileNewVcd = new QAction( QIcon::fromTheme( "media-optical-video" ), i18n("New &Video CD Project"), this );
0341     actionFileNewVcd->setToolTip( i18n("Creates a new Video CD project") );
0342     actionFileNewVcd->setStatusTip( actionFileNewVcd->toolTip() );
0343     actionCollection()->addAction( "file_new_vcd", actionFileNewVcd );
0344     connect( actionFileNewVcd, SIGNAL(triggered(bool)), this, SLOT(slotNewVcdDoc()) );
0345 
0346     QAction* actionFileNewMovix = new QAction( QIcon::fromTheme( "media-optical-video" ), i18n("New &eMovix Project"), this );
0347     actionFileNewMovix->setToolTip( i18n("Creates a new eMovix project") );
0348     actionFileNewMovix->setStatusTip( actionFileNewMovix->toolTip() );
0349     actionCollection()->addAction( "file_new_movix", actionFileNewMovix );
0350     connect( actionFileNewMovix, SIGNAL(triggered(bool)), this, SLOT(slotNewMovixDoc()) );
0351 
0352     QAction* actionFileNewVideoDvd = new QAction( QIcon::fromTheme( "media-optical-video" ), i18n("New V&ideo DVD Project"), this );
0353     actionFileNewVideoDvd->setToolTip( i18n("Creates a new Video DVD project") );
0354     actionFileNewVideoDvd->setStatusTip( actionFileNewVideoDvd->toolTip() );
0355     actionCollection()->addAction( "file_new_video_dvd", actionFileNewVideoDvd );
0356     connect( actionFileNewVideoDvd, SIGNAL(triggered(bool)), this, SLOT(slotNewVideoDvdDoc()) );
0357 
0358     QAction* actionFileContinueMultisession = new QAction( QIcon::fromTheme( "media-optical-data" ), i18n("Continue Multisession Project"), this );
0359     actionFileContinueMultisession->setToolTip( i18n( "Continues multisession project" ) );
0360     actionFileContinueMultisession->setStatusTip( actionFileContinueMultisession->toolTip() );
0361     actionCollection()->addAction( "file_continue_multisession", actionFileContinueMultisession );
0362     connect( actionFileContinueMultisession, SIGNAL(triggered(bool)), this, SLOT(slotContinueMultisession()) );
0363 
0364     KActionMenu* actionFileNewMenu = new KActionMenu( i18n("&New Project"),this );
0365     actionFileNewMenu->setIcon( QIcon::fromTheme( "document-new" ) );
0366     actionFileNewMenu->setToolTip(i18n("Creates a new project"));
0367     actionFileNewMenu->setStatusTip( actionFileNewMenu->toolTip() );
0368     actionFileNewMenu->setPopupMode( QToolButton::InstantPopup );
0369     actionFileNewMenu->addAction( actionFileNewData );
0370     actionFileNewMenu->addAction( actionFileContinueMultisession );
0371     actionFileNewMenu->addSeparator();
0372     actionFileNewMenu->addAction( actionFileNewAudio );
0373     actionFileNewMenu->addAction( actionFileNewMixed );
0374     actionFileNewMenu->addSeparator();
0375     actionFileNewMenu->addAction( actionFileNewVcd );
0376     actionFileNewMenu->addAction( actionFileNewVideoDvd );
0377     actionFileNewMenu->addSeparator();
0378     actionFileNewMenu->addAction( actionFileNewMovix );
0379     actionCollection()->addAction( "file_new", actionFileNewMenu );
0380 
0381     QAction* actionProjectAddFiles = new QAction( QIcon::fromTheme( "document-open" ), i18n("&Add Files..."), this );
0382     actionProjectAddFiles->setToolTip( i18n("Add files to the current project") );
0383     actionProjectAddFiles->setStatusTip( actionProjectAddFiles->toolTip() );
0384     actionCollection()->addAction( "project_add_files", actionProjectAddFiles );
0385     connect( actionProjectAddFiles, SIGNAL(triggered(bool)), this, SLOT(slotProjectAddFiles()) );
0386 
0387     QAction* actionClearProject = new QAction( QIcon::fromTheme( QApplication::isRightToLeft() ? "edit-clear-locationbar-rtl" : "edit-clear-locationbar-ltr" ), i18n("&Clear Project"), this );
0388     actionClearProject->setToolTip( i18n("Clear the current project") );
0389     actionClearProject->setStatusTip( actionClearProject->toolTip() );
0390     actionCollection()->addAction( "project_clear_project", actionClearProject );
0391     connect( actionClearProject, SIGNAL(triggered(bool)), this, SLOT(slotClearProject()) );
0392 
0393     QAction* actionToolsFormatMedium = new QAction( QIcon::fromTheme( "tools-media-optical-format" ), i18n("&Format/Erase rewritable disk..."), this );
0394     actionToolsFormatMedium->setIconText( i18n( "Format" ) );
0395     actionToolsFormatMedium->setToolTip( i18n("Open the rewritable disk formatting/erasing dialog") );
0396     actionToolsFormatMedium->setStatusTip( actionToolsFormatMedium->toolTip() );
0397     actionCollection()->addAction( "tools_format_medium", actionToolsFormatMedium );
0398     connect( actionToolsFormatMedium, SIGNAL(triggered(bool)), this, SLOT(slotFormatMedium()) );
0399 
0400     QAction* actionToolsWriteImage = new QAction( QIcon::fromTheme( "tools-media-optical-burn-image" ), i18n("&Burn Image..."), this );
0401     actionToolsWriteImage->setToolTip( i18n("Write an ISO 9660, cue/bin, or cdrecord clone image to an optical disc") );
0402     actionToolsWriteImage->setStatusTip( actionToolsWriteImage->toolTip() );
0403     actionCollection()->addAction( "tools_write_image", actionToolsWriteImage );
0404     connect( actionToolsWriteImage, SIGNAL(triggered(bool)), this, SLOT(slotWriteImage()) );
0405 
0406     QAction* actionToolsMediaCopy = new QAction( QIcon::fromTheme( "tools-media-optical-copy" ), i18n("Copy &Medium..."), this );
0407     actionToolsMediaCopy->setIconText( i18n( "Copy" ) );
0408     actionToolsMediaCopy->setToolTip( i18n("Open the media copy dialog") );
0409     actionToolsMediaCopy->setStatusTip( actionToolsMediaCopy->toolTip() );
0410     actionCollection()->addAction( "tools_copy_medium", actionToolsMediaCopy );
0411     connect( actionToolsMediaCopy, SIGNAL(triggered(bool)), this, SLOT(slotMediaCopy()) );
0412 
0413     QAction* actionToolsCddaRip = new QAction( QIcon::fromTheme( "tools-rip-audio-cd" ), i18n("Rip Audio CD..."), this );
0414     actionToolsCddaRip->setToolTip( i18n("Digitally extract tracks from an audio CD") );
0415     actionToolsCddaRip->setStatusTip( actionToolsCddaRip->toolTip() );
0416     actionCollection()->addAction( "tools_cdda_rip", actionToolsCddaRip );
0417     connect( actionToolsCddaRip, SIGNAL(triggered(bool)), this, SLOT(slotCddaRip()) );
0418 
0419     QAction* actionToolsVideoDvdRip = new QAction( QIcon::fromTheme( "tools-rip-video-dvd" ), i18n("Rip Video DVD..."), this );
0420     actionToolsVideoDvdRip->setToolTip( i18n("Transcode Video DVD titles") );
0421     actionToolsVideoDvdRip->setStatusTip( actionToolsVideoDvdRip->toolTip() );
0422     connect( actionToolsVideoDvdRip, SIGNAL(triggered(bool)), this, SLOT(slotVideoDvdRip()) );
0423     actionCollection()->addAction( "tools_videodvd_rip", actionToolsVideoDvdRip );
0424 
0425     QAction* actionToolsVideoCdRip = new QAction( QIcon::fromTheme( "tools-rip-video-cd" ), i18n("Rip Video CD..."), this );
0426     actionToolsVideoCdRip->setToolTip( i18n("Extract tracks from a Video CD") );
0427     actionToolsVideoCdRip->setStatusTip( actionToolsVideoCdRip->toolTip() );
0428     actionCollection()->addAction( "tools_videocd_rip", actionToolsVideoCdRip );
0429     connect( actionToolsVideoCdRip, SIGNAL(triggered(bool)), this, SLOT(slotVideoCdRip()) );
0430 
0431     d->actionViewDocumentHeader = new KToggleAction(i18n("Show Projects Header"),this);
0432     d->actionViewDocumentHeader->setToolTip( i18n("Shows/hides title header of projects panel") );
0433     d->actionViewDocumentHeader->setStatusTip( d->actionViewDocumentHeader->toolTip() );
0434     actionCollection()->addAction("view_document_header", d->actionViewDocumentHeader);
0435 
0436     d->actionViewStatusBar = KStandardAction::showStatusbar(this, SLOT(slotViewStatusBar()), actionCollection());
0437     KStandardAction::showMenubar( this, SLOT(slotShowMenuBar()), actionCollection() );
0438     KStandardAction::keyBindings( this, SLOT(slotConfigureKeys()), actionCollection() );
0439     KStandardAction::configureToolbars(this, SLOT(slotEditToolbars()), actionCollection());
0440     setStandardToolBarMenuEnabled(true);
0441 
0442     QAction* actionSettingsConfigure = KStandardAction::preferences(this, SLOT(slotSettingsConfigure()), actionCollection() );
0443     actionSettingsConfigure->setToolTip( i18n("Configure K3b settings") );
0444     actionSettingsConfigure->setStatusTip( actionSettingsConfigure->toolTip() );
0445 
0446     QAction* actionHelpSystemCheck = new QAction( i18n("System Check"), this );
0447     actionHelpSystemCheck->setToolTip( i18n("Checks system configuration") );
0448     actionHelpSystemCheck->setStatusTip( actionHelpSystemCheck->toolTip() );
0449     actionCollection()->addAction( "help_check_system", actionHelpSystemCheck );
0450     connect( actionHelpSystemCheck, SIGNAL(triggered(bool)), this, SLOT(slotManualCheckSystem()) );
0451 }
0452 
0453 
0454 
0455 QList<K3b::Doc*> K3b::MainWindow::projects() const
0456 {
0457     return k3bappcore->projectManager()->projects();
0458 }
0459 
0460 
0461 void K3b::MainWindow::slotConfigureKeys()
0462 {
0463     KShortcutsDialog::showDialog( actionCollection(), KShortcutsEditor::LetterShortcutsDisallowed, this );
0464 }
0465 
0466 void K3b::MainWindow::initStatusBar()
0467 {
0468     d->statusBarManager = new K3b::StatusBarManager( this );
0469 }
0470 
0471 
0472 void K3b::MainWindow::initView()
0473 {
0474     // setup main docking things
0475     d->mainSplitter = new QSplitter( Qt::Vertical, this );
0476     
0477     QSplitter* upperSplitter = new QSplitter( Qt::Horizontal, d->mainSplitter );
0478     d->mainSplitter->addWidget( upperSplitter );
0479 
0480     // --- Document Dock ----------------------------------------------------------------------------
0481     d->documentStack = new QStackedWidget( d->mainSplitter );
0482     d->mainSplitter->addWidget( d->documentStack );
0483     d->documentHull = new QWidget( d->documentStack );
0484     QGridLayout* documentHullLayout = new QGridLayout( d->documentHull );
0485     documentHullLayout->setContentsMargins( 0, 0, 0, 0 );
0486     documentHullLayout->setSpacing( 0 );
0487     
0488     setCentralWidget( d->mainSplitter );
0489     setEqualSizes( d->mainSplitter );
0490 
0491     d->documentHeader = new K3b::ThemedHeader( d->documentHull );
0492     d->documentHeader->setTitle( i18n("Current Projects") );
0493     d->documentHeader->setAlignment( Qt::AlignHCenter | Qt::AlignVCenter );
0494     d->documentHeader->setLeftPixmap( K3b::Theme::PROJECT_LEFT );
0495     d->documentHeader->setRightPixmap( K3b::Theme::PROJECT_RIGHT );
0496     connect( d->actionViewDocumentHeader, SIGNAL(toggled(bool)),
0497              d->documentHeader, SLOT(setVisible(bool)) );
0498 
0499     // add the document tab to the styled document box
0500     d->documentTab = new K3b::ProjectTabWidget( d->documentHull );
0501 
0502     documentHullLayout->addWidget( d->documentHeader, 0, 0 );
0503     documentHullLayout->addWidget( d->documentTab, 1, 0 );
0504 
0505     connect( d->documentTab, SIGNAL(currentChanged(int)), this, SLOT(slotCurrentDocChanged()) );
0506     connect( d->documentTab, SIGNAL(tabCloseRequested(Doc*)), this, SLOT(slotFileClose(Doc*)) );
0507 
0508     d->welcomeWidget = new K3b::WelcomeWidget( this, d->documentStack );
0509     d->documentStack->addWidget( d->welcomeWidget );
0510     d->documentStack->addWidget( d->documentHull );
0511     d->documentStack->setCurrentWidget( d->welcomeWidget );
0512     // ---------------------------------------------------------------------------------------------
0513 
0514     // --- Directory Dock --------------------------------------------------------------------------
0515     K3b::FileTreeView* fileTreeView = new K3b::FileTreeView( upperSplitter );
0516     upperSplitter->addWidget( fileTreeView );
0517     // ---------------------------------------------------------------------------------------------
0518 
0519 
0520     // --- Contents Dock ---------------------------------------------------------------------------
0521     d->dirView = new K3b::DirView( fileTreeView, upperSplitter );
0522     upperSplitter->addWidget( d->dirView );
0523 
0524     // --- filetreecombobox-toolbar ----------------------------------------------------------------
0525     d->filePlacesModel = new KFilePlacesModel;
0526     d->urlNavigator = new K3b::UrlNavigator(d->filePlacesModel, this);
0527     connect( d->urlNavigator, SIGNAL(activated(QUrl)), d->dirView, SLOT(showUrl(QUrl)) );
0528     connect( d->urlNavigator, SIGNAL(activated(K3b::Device::Device*)), d->dirView, SLOT(showDevice(K3b::Device::Device*)) );
0529     connect( d->dirView, SIGNAL(urlEntered(QUrl)), d->urlNavigator, SLOT(setUrl(QUrl)) );
0530     connect( d->dirView, SIGNAL(deviceSelected(K3b::Device::Device*)), d->urlNavigator, SLOT(setDevice(K3b::Device::Device*)) );
0531     QWidgetAction * urlNavigatorAction = new QWidgetAction(this);
0532     urlNavigatorAction->setDefaultWidget(d->urlNavigator);
0533     urlNavigatorAction->setText(i18n("&Location Bar"));
0534     actionCollection()->addAction( "location_bar", urlNavigatorAction );
0535     // ---------------------------------------------------------------------------------------------
0536 }
0537 
0538 
0539 void K3b::MainWindow::createClient( K3b::Doc* doc )
0540 {
0541     qDebug();
0542 
0543     // create the proper K3b::View (maybe we should put this into some other class like K3b::ProjectManager)
0544     K3b::View* view = 0;
0545     switch( doc->type() ) {
0546     case K3b::Doc::AudioProject:
0547         view = new K3b::AudioView( static_cast<K3b::AudioDoc*>(doc), d->documentTab );
0548         break;
0549     case K3b::Doc::DataProject:
0550         view = new K3b::DataView( static_cast<K3b::DataDoc*>(doc), d->documentTab );
0551         break;
0552     case K3b::Doc::MixedProject:
0553     {
0554         K3b::MixedDoc* mixedDoc = static_cast<K3b::MixedDoc*>(doc);
0555         view = new K3b::MixedView( mixedDoc, d->documentTab );
0556         mixedDoc->dataDoc()->setView( view );
0557         mixedDoc->audioDoc()->setView( view );
0558         break;
0559     }
0560     case K3b::Doc::VcdProject:
0561         view = new K3b::VcdView( static_cast<K3b::VcdDoc*>(doc), d->documentTab );
0562         break;
0563     case K3b::Doc::MovixProject:
0564         view = new K3b::MovixView( static_cast<K3b::MovixDoc*>(doc), d->documentTab );
0565         break;
0566     case K3b::Doc::VideoDvdProject:
0567         view = new K3b::VideoDvdView( static_cast<K3b::VideoDvdDoc*>(doc), d->documentTab );
0568         break;
0569     }
0570 
0571     if( view != 0 ) {
0572         doc->setView( view );
0573         view->setWindowTitle( doc->URL().fileName() );
0574 
0575         d->documentTab->addTab( doc );
0576         d->documentTab->setCurrentTab( doc );
0577 
0578         slotCurrentDocChanged();
0579     }
0580 }
0581 
0582 
0583 K3b::View* K3b::MainWindow::activeView() const
0584 {
0585     if( Doc* doc = activeDoc() )
0586         return qobject_cast<View*>( doc->view() );
0587     else
0588         return 0;
0589 }
0590 
0591 
0592 K3b::Doc* K3b::MainWindow::activeDoc() const
0593 {
0594     return d->documentTab->currentTab();
0595 }
0596 
0597 
0598 K3b::Doc* K3b::MainWindow::openDocument(const QUrl& url)
0599 {
0600     slotStatusMsg(i18n("Opening file..."));
0601 
0602     //
0603     // First we check if this is an iso image in case someone wants to open one this way
0604     //
0605     if( isDiscImage( url ) ) {
0606         slotWriteImage( url );
0607         return 0;
0608     }
0609     else {
0610         // see if it's an audio cue file
0611         K3b::CueFileParser parser( url.toLocalFile() );
0612         if( parser.isValid() && parser.toc().contentType() == K3b::Device::AUDIO ) {
0613             K3b::Doc* doc = k3bappcore->projectManager()->createProject( K3b::Doc::AudioProject );
0614             doc->addUrl( url );
0615             return doc;
0616         }
0617         else {
0618             // check, if document already open. If yes, set the focus to the first view
0619             K3b::Doc* doc = k3bappcore->projectManager()->findByUrl( url );
0620             if( doc ) {
0621                 d->documentTab->setCurrentTab( doc );
0622                 return doc;
0623             }
0624 
0625             doc = k3bappcore->projectManager()->openProject( url );
0626 
0627             if( doc == 0 ) {
0628                 KMessageBox::error (this,i18n("Could not open document."), i18n("Error"));
0629                 return 0;
0630             }
0631 
0632             d->actionFileOpenRecent->addUrl(url);
0633 
0634             return doc;
0635         }
0636     }
0637 }
0638 
0639 
0640 void K3b::MainWindow::saveOptions()
0641 {
0642     KConfigGroup recentGrp(config(), QStringLiteral("Recent Files"));
0643     d->actionFileOpenRecent->saveEntries( recentGrp );
0644 
0645     KConfigGroup grpFileView( config(), QStringLiteral("file view") );
0646     d->dirView->saveConfig( grpFileView );
0647 
0648     KConfigGroup grpWindows(config(), QStringLiteral("main_window_settings"));
0649     saveMainWindowSettings( grpWindows );
0650 
0651     k3bcore->saveSettings( config() );
0652 
0653     KConfigGroup grp(config(), QStringLiteral("Welcome Widget") );
0654     d->welcomeWidget->saveConfig( grp );
0655 
0656     KConfigGroup grpOption( config(), QStringLiteral("General Options") );
0657     grpOption.writeEntry( "Show Document Header", d->actionViewDocumentHeader->isChecked() );
0658     grpOption.writeEntry( "Navigator breadcrumb mode", !d->urlNavigator->isUrlEditable() );
0659 
0660     config()->sync();
0661 }
0662 
0663 
0664 void K3b::MainWindow::readOptions()
0665 {
0666     KConfigGroup grpWindow(config(), QStringLiteral("main_window_settings"));
0667     applyMainWindowSettings( grpWindow );
0668     
0669     KConfigGroup grp( config(), QStringLiteral("General Options") );
0670     d->actionViewDocumentHeader->setChecked( grp.readEntry("Show Document Header", true) );
0671     d->urlNavigator->setUrlEditable( !grp.readEntry( "Navigator breadcrumb mode", true ) );
0672 
0673     // initialize the recent file list
0674     KConfigGroup recentGrp(config(), QStringLiteral("Recent Files"));
0675     d->actionFileOpenRecent->loadEntries( recentGrp );
0676 
0677     KConfigGroup grpFileView( config(), QStringLiteral("file view") );
0678     d->dirView->readConfig( grpFileView );
0679 
0680     d->documentHeader->setVisible( d->actionViewDocumentHeader->isChecked() );
0681 }
0682 
0683 
0684 void K3b::MainWindow::saveProperties( KConfigGroup& grp )
0685 {
0686     // 1. put saved projects in the config
0687     // 2. save every modified project in  "~/.kde/share/apps/k3b/sessions/" + KApp->sessionId()
0688     // 3. save the url of the project (might be something like "AudioCD1") in the config
0689     // 4. save the status of every project (modified/saved)
0690 
0691     QString saveDir = QString( "%1/sessions/%2/" ).arg(
0692                 QStandardPaths::writableLocation( QStandardPaths::AppDataLocation ),
0693                 qApp->sessionId() );
0694     QDir().mkpath(saveDir);
0695 
0696 //     // FIXME: for some reason the config entries are not properly stored when using the default
0697 //     //        KMainWindow session config. Since I was not able to find the bug I use another config object
0698 //     // ----------------------------------------------------------
0699 //     KConfig c( saveDir + "list", KConfig::SimpleConfig );
0700 //     KConfigGroup grp( &c, "Saved Session" );
0701 //     // ----------------------------------------------------------
0702 
0703     QList<K3b::Doc*> docs = k3bappcore->projectManager()->projects();
0704     grp.writeEntry( "Number of projects", docs.count() );
0705 
0706     int cnt = 1;
0707     Q_FOREACH( K3b::Doc* doc, docs ) {
0708         // the "name" of the project (or the original url if isSaved())
0709         grp.writePathEntry( QString("%1 url").arg(cnt), (doc)->URL().url() );
0710 
0711         // is the doc modified
0712         grp.writeEntry( QString("%1 modified").arg(cnt), (doc)->isModified() );
0713 
0714         // has the doc already been saved?
0715         grp.writeEntry( QString("%1 saved").arg(cnt), (doc)->isSaved() );
0716 
0717         // where does the session management save it? If it's not modified and saved this is
0718         // the same as the url
0719         QUrl saveUrl = (doc)->URL();
0720         if( !(doc)->isSaved() || (doc)->isModified() )
0721             saveUrl = QUrl::fromLocalFile( saveDir + QString::number(cnt) );
0722         grp.writePathEntry( QString("%1 saveurl").arg(cnt), saveUrl.url() );
0723 
0724         // finally save it
0725         k3bappcore->projectManager()->saveProject( doc, saveUrl );
0726 
0727         ++cnt;
0728     }
0729 
0730 //    c.sync();
0731 }
0732 
0733 
0734 // FIXME:move this to K3b::ProjectManager
0735 void K3b::MainWindow::readProperties( const KConfigGroup& grp )
0736 {
0737     // FIXME: do not delete the files here. rather do it when the app is exited normally
0738     //        since that's when we can be sure we never need the session stuff again.
0739 
0740     // 1. read all projects from the config
0741     // 2. simply open all of them
0742     // 3. reset the saved urls and the modified state
0743     // 4. delete "~/.kde/share/apps/k3b/sessions/" + KApp->sessionId()
0744 
0745     QString saveDir = QString( "%1/sessions/%2/" ).arg(
0746                 QStandardPaths::writableLocation( QStandardPaths::AppDataLocation ),
0747                 qApp->sessionId() );
0748     QDir().mkpath(saveDir);
0749 
0750 //     // FIXME: for some reason the config entries are not properly stored when using the default
0751 //     //        KMainWindow session config. Since I was not able to find the bug I use another config object
0752 //     // ----------------------------------------------------------
0753 //     KConfig c( saveDir + "list"/*, true*/ );
0754 //     KConfigGroup grp( &c, "Saved Session" );
0755 //     // ----------------------------------------------------------
0756 
0757     int cnt = grp.readEntry( "Number of projects", 0 );
0758 /*
0759   qDebug() << "(K3b::MainWindow::readProperties) number of projects from last session in " << saveDir << ": " << cnt << Qt::endl
0760   << "                                read from config group " << c->group() << Qt::endl;
0761 */
0762     for( int i = 1; i <= cnt; ++i ) {
0763         // in this case the constructor works since we saved as url()
0764         QUrl url( grp.readPathEntry( QString("%1 url").arg(i),QString() ) );
0765 
0766         bool modified = grp.readEntry( QString("%1 modified").arg(i),false );
0767 
0768         bool saved = grp.readEntry( QString("%1 saved").arg(i),false );
0769 
0770         QUrl saveUrl( grp.readPathEntry( QString("%1 saveurl").arg(i),QString() ) );
0771 
0772         // now load the project
0773         if( K3b::Doc* doc = k3bappcore->projectManager()->openProject( saveUrl ) ) {
0774 
0775             // reset the url
0776             doc->setURL( url );
0777             doc->setModified( modified );
0778             doc->setSaved( saved );
0779         }
0780         else
0781             qDebug() << "(K3b::MainWindow) could not open session saved doc " << url.toLocalFile();
0782 
0783         // remove the temp file
0784         if( !saved || modified )
0785             QFile::remove( saveUrl.toLocalFile() );
0786     }
0787 
0788     // and now remove the temp dir
0789     KIO::del( QUrl::fromLocalFile(saveDir), KIO::HideProgressInfo );
0790 }
0791 
0792 
0793 bool K3b::MainWindow::queryClose()
0794 {
0795     //
0796     // Check if a job is currently running
0797     // For now K3b only allows for one major job at a time which means that we only need to cancel
0798     // this one job.
0799     //
0800     if( k3bcore->jobsRunning() ) {
0801 
0802         // pitty, but I see no possibility to make this work. It always crashes because of the event
0803         // management thing mentioned below. So until I find a solution K3b simply will refuse to close
0804         // while a job i running
0805         return false;
0806 
0807 //     qDebug() << "(K3b::MainWindow::queryClose) jobs running.";
0808 //     K3b::Job* job = k3bcore->runningJobs().getFirst();
0809 
0810 //     // now search for the major job (to be on the safe side although for now no subjobs register with the k3bcore)
0811 //     K3b::JobHandler* jh = job->jobHandler();
0812 //     while( jh->isJob() ) {
0813 //       job = static_cast<K3b::Job*>( jh );
0814 //       jh = job->jobHandler();
0815 //     }
0816 
0817 //     qDebug() << "(K3b::MainWindow::queryClose) main job found: " << job->jobDescription();
0818 
0819 //     // now job is the major job and jh should be a widget
0820 //     QWidget* progressDialog = dynamic_cast<QWidget*>( jh );
0821 
0822 //     qDebug() << "(K3b::MainWindow::queryClose) job active: " << job->active();
0823 
0824 //     // now ask the user if he/she really wants to cancel this job
0825 //     if( job->active() ) {
0826 //       if( KMessageBox::questionYesNo( progressDialog ? progressDialog : this,
0827 //                    i18n("Do you really want to cancel?"),
0828 //                    i18n("Cancel") ) == KMessageBox::Yes ) {
0829 //  // cancel the job
0830 //  qDebug() << "(K3b::MainWindow::queryClose) canceling job.";
0831 //  job->cancel();
0832 
0833 //  // wait for the job to finish
0834 //  qDebug() << "(K3b::MainWindow::queryClose) waiting for job to finish.";
0835 //  K3b::SignalWaiter::waitForJob( job );
0836 
0837 //  // close the progress dialog
0838 //  if( progressDialog ) {
0839 //    qDebug() << "(K3b::MainWindow::queryClose) closing progress dialog.";
0840 //    progressDialog->close();
0841 //    //
0842 //    // now here we have the problem that due to the whole Qt event thing the exec call (or
0843 //    // in this case most likely the startJob call) does not return until we leave this method.
0844 //    // That means that the progress dialog might be deleted by it's parent below (when we
0845 //    // close docs) before it is deleted by the creator (most likely a projectburndialog).
0846 //    // That would result in a double deletion and thus a crash.
0847 //    // So we just reparent the dialog to 0 here so it's (former) parent won't delete it.
0848 //    //
0849 //    progressDialog->reparent( 0, QPoint(0,0) );
0850 //  }
0851 
0852 //  qDebug() << "(K3b::MainWindow::queryClose) job cleanup done.";
0853 //       }
0854 //       else
0855 //  return false;
0856 //     }
0857     }
0858     saveOptions();
0859 
0860     //
0861     // if we are closed by the session manager everything is fine since we store the
0862     // current state in saveProperties
0863     //
0864     if( qApp->isSavingSession() )
0865         return true;
0866 
0867     // FIXME: do not close the docs here. Just ask for them to be saved and return false
0868     //        if the user chose cancel for some doc
0869 
0870     // ---------------------------------
0871     // we need to manually close all the views to ensure that
0872     // each of them receives a close-event and
0873     // the user is asked for every modified doc to save the changes
0874     // ---------------------------------
0875 
0876     while( K3b::View* view = activeView() ) {
0877         if( !canCloseDocument(view->doc()) )
0878             return false;
0879         closeProject(view->doc());
0880     }
0881 
0882     return true;
0883 }
0884 
0885 
0886 bool K3b::MainWindow::canCloseDocument( K3b::Doc* doc )
0887 {
0888     if( !doc->isModified() )
0889         return true;
0890 
0891     if( !KConfigGroup( config(), QStringLiteral("General Options") ).readEntry( "ask_for_saving_changes_on_exit", true ) )
0892         return true;
0893 
0894     switch ( KMessageBox::warningTwoActionsCancel( this,
0895                                                    xi18nc("@info", "Project <resource>%1</resource> has unsaved data.", doc->URL().fileName() ),
0896                                                    i18n("Closing Project"),
0897                                                    KStandardGuiItem::save(),
0898                                                    KStandardGuiItem::discard() ) ) {
0899     case KMessageBox::PrimaryAction:
0900         return fileSave( doc );
0901     case KMessageBox::SecondaryAction:
0902         return true;
0903     default:
0904         return false;
0905     }
0906 }
0907 
0908 
0909 /////////////////////////////////////////////////////////////////////
0910 // SLOT IMPLEMENTATION
0911 /////////////////////////////////////////////////////////////////////
0912 
0913 
0914 void K3b::MainWindow::slotFileOpen()
0915 {
0916     slotStatusMsg(i18n("Opening file..."));
0917 
0918     QList<QUrl> urls = QFileDialog::getOpenFileUrls( this,
0919                                                      i18n("Open Files"),
0920                                                      QUrl(),
0921                                                      i18n("K3b Projects (*.k3b)"));
0922     for( QList<QUrl>::iterator it = urls.begin(); it != urls.end(); ++it ) {
0923         openDocument( *it );
0924         d->actionFileOpenRecent->addUrl( *it );
0925     }
0926 }
0927 
0928 void K3b::MainWindow::slotFileOpenRecent(const QUrl& url)
0929 {
0930     slotStatusMsg(i18n("Opening file..."));
0931 
0932     openDocument(url);
0933 }
0934 
0935 
0936 void K3b::MainWindow::slotFileSaveAll()
0937 {
0938     Q_FOREACH( K3b::Doc* doc, k3bappcore->projectManager()->projects() ) {
0939         fileSave( doc );
0940     }
0941 }
0942 
0943 
0944 void K3b::MainWindow::slotFileSave()
0945 {
0946     if( K3b::Doc* doc = activeDoc() ) {
0947         fileSave( doc );
0948     }
0949 }
0950 
0951 bool K3b::MainWindow::fileSave( K3b::Doc* doc )
0952 {
0953     slotStatusMsg(i18n("Saving file..."));
0954 
0955     if( doc == 0 ) {
0956         doc = activeDoc();
0957     }
0958 
0959     if( doc != 0 ) {
0960         if( !doc->isSaved() )
0961             return fileSaveAs( doc );
0962         else if( !k3bappcore->projectManager()->saveProject( doc, doc->URL()) )
0963             KMessageBox::error (this,i18n("Could not save the current document."), i18n("I/O Error"));
0964     }
0965 
0966     return false;
0967 }
0968 
0969 
0970 void K3b::MainWindow::slotFileSaveAs()
0971 {
0972     if( K3b::Doc* doc = activeDoc() ) {
0973         fileSaveAs( doc );
0974     }
0975 }
0976 
0977 
0978 bool K3b::MainWindow::fileSaveAs( K3b::Doc* doc )
0979 {
0980     slotStatusMsg(i18n("Saving file with a new filename..."));
0981 
0982     if( !doc ) {
0983         doc = activeDoc();
0984     }
0985 
0986     if( doc ) {
0987         // we do not use the static QFileDialog method here to be able to specify a filename suggestion
0988         QFileDialog dlg( this, i18n("Save As"), QString(), i18n("K3b Projects (*.k3b)") );
0989         dlg.setAcceptMode( QFileDialog::AcceptSave );
0990         dlg.selectFile( doc->name() );
0991         dlg.exec();
0992         QList<QUrl> urls = dlg.selectedUrls();
0993 
0994         if( !urls.isEmpty() ) {
0995             QUrl url = urls.front();
0996             KRecentDocument::add( url );
0997 
0998             if( k3bappcore->projectManager()->saveProject( doc, url ) ) {
0999                 d->actionFileOpenRecent->addUrl(url);
1000                 return true;
1001             }
1002             else {
1003                 KMessageBox::error (this,i18n("Could not save the current document."), i18n("I/O Error"));
1004             }
1005         }
1006     }
1007 
1008     return false;
1009 }
1010 
1011 
1012 void K3b::MainWindow::slotFileClose()
1013 {
1014     if( K3b::View* view = activeView() ) {
1015         slotFileClose( view->doc() );
1016     }
1017 }
1018 
1019 
1020 void K3b::MainWindow::slotFileClose( Doc* doc )
1021 {
1022     slotStatusMsg(i18n("Closing file..."));
1023     if( doc && canCloseDocument(doc) ) {
1024         closeProject(doc);
1025     }
1026 
1027     slotCurrentDocChanged();
1028 }
1029 
1030 
1031 void K3b::MainWindow::slotFileCloseAll()
1032 {
1033     while( K3b::View* view = activeView() ) {
1034         K3b::Doc* doc = view->doc();
1035 
1036         if( canCloseDocument(doc) )
1037             closeProject(doc);
1038         else
1039             break;
1040     }
1041 
1042     slotCurrentDocChanged();
1043 }
1044 
1045 
1046 void K3b::MainWindow::closeProject( K3b::Doc* doc )
1047 {
1048     // unplug the actions
1049     if( factory() ) {
1050         if( d->lastDoc == doc ) {
1051             factory()->removeClient( static_cast<K3b::View*>(d->lastDoc->view()) );
1052             d->lastDoc = 0;
1053         }
1054     }
1055 
1056     // remove the doc from the project tab
1057     d->documentTab->removeTab( doc );
1058 
1059     // remove the project from the manager
1060     k3bappcore->projectManager()->removeProject( doc );
1061 
1062     // delete view and doc
1063     delete doc->view();
1064     delete doc;
1065 }
1066 
1067 
1068 void K3b::MainWindow::slotFileQuit()
1069 {
1070     close();
1071 }
1072 
1073 
1074 void K3b::MainWindow::slotViewStatusBar()
1075 {
1076     //turn Statusbar on or off
1077     if(d->actionViewStatusBar->isChecked()) {
1078         statusBar()->show();
1079     }
1080     else {
1081         statusBar()->hide();
1082     }
1083 }
1084 
1085 
1086 void K3b::MainWindow::slotStatusMsg(const QString &text)
1087 {
1088     ///////////////////////////////////////////////////////////////////
1089     // change status message permanently
1090 //   statusBar()->clear();
1091 //   statusBar()->setItemText(text,1);
1092 
1093     statusBar()->showMessage( text, 2000 );
1094 }
1095 
1096 
1097 void K3b::MainWindow::slotSettingsConfigure()
1098 {
1099     K3b::OptionDialog d( this );
1100 
1101     d.exec();
1102 
1103     // emit a changed signal every time since we do not know if the user selected
1104     // "apply" and "cancel" or "ok"
1105     emit configChanged( config() );
1106 }
1107 
1108 
1109 void K3b::MainWindow::showOptionDialog( K3b::OptionDialog::ConfigPage index )
1110 {
1111     K3b::OptionDialog d( this);
1112     d.setCurrentPage( index );
1113 
1114     d.exec();
1115 
1116     // emit a changed signal every time since we do not know if the user selected
1117     // "apply" and "cancel" or "ok"
1118     emit configChanged( config() );
1119 }
1120 
1121 
1122 K3b::Doc* K3b::MainWindow::slotNewAudioDoc()
1123 {
1124     slotStatusMsg(i18n("Creating new Audio CD Project."));
1125 
1126     K3b::Doc* doc = k3bappcore->projectManager()->createProject( K3b::Doc::AudioProject );
1127 
1128     return doc;
1129 }
1130 
1131 K3b::Doc* K3b::MainWindow::slotNewDataDoc()
1132 {
1133     slotStatusMsg(i18n("Creating new Data CD Project."));
1134 
1135     K3b::Doc* doc = k3bappcore->projectManager()->createProject( K3b::Doc::DataProject );
1136 
1137     return doc;
1138 }
1139 
1140 
1141 K3b::Doc* K3b::MainWindow::slotContinueMultisession()
1142 {
1143     return K3b::DataMultisessionImportDialog::importSession( 0, this );
1144 }
1145 
1146 
1147 K3b::Doc* K3b::MainWindow::slotNewVideoDvdDoc()
1148 {
1149     slotStatusMsg(i18n("Creating new Video DVD Project."));
1150 
1151     K3b::Doc* doc = k3bappcore->projectManager()->createProject( K3b::Doc::VideoDvdProject );
1152 
1153     return doc;
1154 }
1155 
1156 
1157 K3b::Doc* K3b::MainWindow::slotNewMixedDoc()
1158 {
1159     slotStatusMsg(i18n("Creating new Mixed Mode CD Project."));
1160 
1161     K3b::Doc* doc = k3bappcore->projectManager()->createProject( K3b::Doc::MixedProject );
1162 
1163     return doc;
1164 }
1165 
1166 K3b::Doc* K3b::MainWindow::slotNewVcdDoc()
1167 {
1168     slotStatusMsg(i18n("Creating new Video CD Project."));
1169 
1170     K3b::Doc* doc = k3bappcore->projectManager()->createProject( K3b::Doc::VcdProject );
1171 
1172     return doc;
1173 }
1174 
1175 
1176 K3b::Doc* K3b::MainWindow::slotNewMovixDoc()
1177 {
1178     slotStatusMsg(i18n("Creating new eMovix Project."));
1179 
1180     K3b::Doc* doc = k3bappcore->projectManager()->createProject( K3b::Doc::MovixProject );
1181 
1182     return doc;
1183 }
1184 
1185 
1186 void K3b::MainWindow::slotCurrentDocChanged()
1187 {
1188     // check the doctype
1189     K3b::View* v = activeView();
1190     if( v ) {
1191         k3bappcore->projectManager()->setActive( v->doc() );
1192 
1193         //
1194         // There are two possiblities to plug the project actions:
1195         // 1. Through KXMLGUIClient::plugActionList
1196         //    This way we just ask the View for the actionCollection (which it should merge with
1197         //    the doc's) and plug it into the project menu.
1198         //    Advantage: easy and clear to handle
1199         //    Disadvantage: we may only plug all actions at once into one menu
1200         //
1201         // 2. Through merging the doc as a KXMLGUIClient
1202         //    This way every view is a KXMLGUIClient and it's GUI is just merged into the MainWindow's.
1203         //    Advantage: flexible
1204         //    Disadvantage: every view needs it's own XML file
1205         //
1206         //
1207 
1208         if( factory() ) {
1209             if( d->lastDoc )
1210                 factory()->removeClient( static_cast<K3b::View*>(d->lastDoc->view()) );
1211             factory()->addClient( v );
1212             d->lastDoc = v->doc();
1213         }
1214         else
1215             qDebug() << "(K3b::MainWindow) ERROR: could not get KXMLGUIFactory instance.";
1216     }
1217     else
1218         k3bappcore->projectManager()->setActive( 0L );
1219 
1220     if( k3bappcore->projectManager()->isEmpty() ) {
1221         slotStateChanged( "state_project_active", KXMLGUIClient::StateReverse );
1222     }
1223     else {
1224         slotStateChanged( "state_project_active", KXMLGUIClient::StateNoReverse );
1225     }
1226 
1227     if( k3bappcore->projectManager()->isEmpty() )
1228         d->documentStack->setCurrentWidget( d->welcomeWidget );
1229     else
1230         d->documentStack->setCurrentWidget( d->documentHull );
1231 }
1232 
1233 
1234 void K3b::MainWindow::slotEditToolbars()
1235 {
1236     KConfigGroup grp( config(), QStringLiteral("main_window_settings") );
1237     saveMainWindowSettings( grp );
1238     KEditToolBar dlg( factory() );
1239     connect( &dlg, SIGNAL(newToolbarConfig()), SLOT(slotNewToolBarConfig()) );
1240     dlg.exec();
1241 }
1242 
1243 
1244 void K3b::MainWindow::slotNewToolBarConfig()
1245 {
1246     KConfigGroup grp(config(), QStringLiteral("main_window_settings"));
1247     applyMainWindowSettings(grp);
1248 }
1249 
1250 
1251 bool K3b::MainWindow::eject()
1252 {
1253     KConfigGroup c( config(), QStringLiteral("General Options") );
1254     return !c.readEntry( "No cd eject", false );
1255 }
1256 
1257 
1258 void K3b::MainWindow::slotErrorMessage(const QString& message)
1259 {
1260     KMessageBox::error( this, message );
1261 }
1262 
1263 
1264 void K3b::MainWindow::slotWarningMessage(const QString& message)
1265 {
1266     KMessageBox::error( this, message );
1267 }
1268 
1269 
1270 void K3b::MainWindow::slotWriteImage()
1271 {
1272     K3b::ImageWritingDialog d( this );
1273     d.exec();
1274 }
1275 
1276 
1277 void K3b::MainWindow::slotWriteImage( const QUrl& url )
1278 {
1279     K3b::ImageWritingDialog d( this );
1280     d.setImage( url );
1281     d.exec();
1282 }
1283 
1284 
1285 void K3b::MainWindow::slotProjectAddFiles()
1286 {
1287     K3b::View* view = activeView();
1288 
1289     if( view ) {
1290         const QList<QUrl> urls = QFileDialog::getOpenFileUrls(this,
1291                                                               i18n("Select Files to Add to Project"),
1292                                                               QUrl(),
1293                                                               i18n("All Files (*)") );
1294 
1295 
1296         if( !urls.isEmpty() )
1297             view->addUrls( urls );
1298     }
1299     else
1300         KMessageBox::error( this, i18n("Please create a project before adding files"), i18n("No Active Project"));
1301 }
1302 
1303 
1304 void K3b::MainWindow::formatMedium( K3b::Device::Device* dev )
1305 {
1306     K3b::MediaFormattingDialog d( this );
1307     d.setDevice( dev );
1308     d.exec();
1309 }
1310 
1311 
1312 void K3b::MainWindow::slotFormatMedium()
1313 {
1314     formatMedium( 0 );
1315 }
1316 
1317 
1318 void K3b::MainWindow::mediaCopy( K3b::Device::Device* dev )
1319 {
1320     K3b::MediaCopyDialog d( this );
1321     d.setReadingDevice( dev );
1322     d.exec();
1323 }
1324 
1325 
1326 void K3b::MainWindow::slotMediaCopy()
1327 {
1328     mediaCopy( 0 );
1329 }
1330 
1331 
1332 // void K3b::MainWindow::slotVideoDvdCopy()
1333 // {
1334 //   K3b::VideoDvdCopyDialog d( this );
1335 //   d.exec();
1336 // }
1337 
1338 
1339 
1340 void K3b::MainWindow::slotShowMenuBar()
1341 {
1342     if( menuBar()->isVisible() )
1343         menuBar()->hide();
1344     else
1345         menuBar()->show();
1346 }
1347 
1348 
1349 K3b::ExternalBinManager* K3b::MainWindow::externalBinManager() const
1350 {
1351     return k3bcore->externalBinManager();
1352 }
1353 
1354 
1355 K3b::Device::DeviceManager* K3b::MainWindow::deviceManager() const
1356 {
1357     return k3bcore->deviceManager();
1358 }
1359 
1360 
1361 void K3b::MainWindow::slotDataImportSession()
1362 {
1363     if( activeView() ) {
1364         if( K3b::DataView* view = qobject_cast<K3b::DataView*>(activeView()) ) {
1365             view->actionCollection()->action( "project_data_import_session" )->trigger();
1366         }
1367     }
1368 }
1369 
1370 
1371 void K3b::MainWindow::slotDataClearImportedSession()
1372 {
1373     if( activeView() ) {
1374         if( K3b::DataView* view = qobject_cast<K3b::DataView*>(activeView()) ) {
1375             view->actionCollection()->action( "project_data_clear_imported_session" )->trigger();
1376         }
1377     }
1378 }
1379 
1380 
1381 void K3b::MainWindow::slotEditBootImages()
1382 {
1383     if( activeView() ) {
1384         if( K3b::DataView* view = qobject_cast<K3b::DataView*>(activeView()) ) {
1385             view->actionCollection()->action( "project_data_edit_boot_images" )->trigger();
1386         }
1387     }
1388 }
1389 
1390 
1391 void K3b::MainWindow::slotCheckSystemTimed()
1392 {
1393     // run the system check from the event queue so we do not
1394     // mess with the device state resetting throughout the app
1395     // when called from K3b::DeviceManager::changed
1396     QTimer::singleShot( 0, this, SLOT(slotCheckSystem()) );
1397 }
1398 
1399 
1400 void K3b::MainWindow::slotCheckSystem()
1401 {
1402     K3b::SystemProblemDialog::checkSystem( this, K3b::SystemProblemDialog::NotifyOnlyErrors );
1403 }
1404 
1405 
1406 void K3b::MainWindow::slotManualCheckSystem()
1407 {
1408     K3b::SystemProblemDialog::checkSystem(this, K3b::SystemProblemDialog::AlwaysNotify, true/* forceCheck */);
1409 }
1410 
1411 
1412 void K3b::MainWindow::addUrls( const QList<QUrl>& urls )
1413 {
1414     if( urls.count() == 1 && isProjectFile( d->mimeDatabase, urls.first() ) ) {
1415         openDocument( urls.first() );
1416     }
1417     else if( K3b::View* view = activeView() ) {
1418         view->addUrls( urls );
1419     }
1420     else if( urls.count() == 1 && isDiscImage( urls.first() ) ) {
1421         slotWriteImage( urls.first() );
1422     }
1423     else if( areAudioFiles( urls ) ) {
1424         static_cast<K3b::View*>(slotNewAudioDoc()->view())->addUrls( urls );
1425     }
1426     else {
1427         static_cast<K3b::View*>(slotNewDataDoc()->view())->addUrls( urls );
1428     }
1429 }
1430 
1431 
1432 void K3b::MainWindow::slotClearProject()
1433 {
1434     K3b::Doc* doc = k3bappcore->projectManager()->activeDoc();
1435     if( doc ) {
1436         if( KMessageBox::warningContinueCancel( this,
1437                                                 i18n("Do you really want to clear the current project?"),
1438                                                 i18n("Clear Project"),
1439                                                 KStandardGuiItem::clear(),
1440                                                 KStandardGuiItem::cancel(),
1441                                                 QString("clear_current_project_dontAskAgain") ) == KMessageBox::Continue ) {
1442             doc->clear();
1443         }
1444     }
1445 
1446 }
1447 
1448 
1449 void K3b::MainWindow::slotCddaRip()
1450 {
1451     cddaRip( 0 );
1452 }
1453 
1454 
1455 void K3b::MainWindow::cddaRip( K3b::Device::Device* dev )
1456 {
1457     if( !dev ||
1458         !(k3bappcore->mediaCache()->medium( dev ).content() & K3b::Medium::ContentAudio ) )
1459         dev = K3b::MediaSelectionDialog::selectMedium( K3b::Device::MEDIA_CD_ALL,
1460                                                      K3b::Device::STATE_COMPLETE|K3b::Device::STATE_INCOMPLETE,
1461                                                      K3b::Medium::ContentAudio,
1462                                                      this,
1463                                                      i18n("Audio CD Rip") );
1464 
1465     if( dev )
1466         d->dirView->showDevice( dev );
1467 }
1468 
1469 
1470 void K3b::MainWindow::videoDvdRip( K3b::Device::Device* dev )
1471 {
1472     if( !dev ||
1473         !(k3bappcore->mediaCache()->medium( dev ).content() & K3b::Medium::ContentVideoDVD ) )
1474         dev = K3b::MediaSelectionDialog::selectMedium( K3b::Device::MEDIA_DVD_ALL,
1475                                                      K3b::Device::STATE_COMPLETE,
1476                                                      K3b::Medium::ContentVideoDVD,
1477                                                      this,
1478                                                      i18n("Video DVD Rip") );
1479 
1480     if( dev )
1481         d->dirView->showDevice( dev );
1482 }
1483 
1484 
1485 void K3b::MainWindow::slotVideoDvdRip()
1486 {
1487     videoDvdRip( 0 );
1488 }
1489 
1490 
1491 void K3b::MainWindow::videoCdRip( K3b::Device::Device* dev )
1492 {
1493     if( !dev ||
1494         !(k3bappcore->mediaCache()->medium( dev ).content() & K3b::Medium::ContentVideoCD ) )
1495         dev = K3b::MediaSelectionDialog::selectMedium( K3b::Device::MEDIA_CD_ALL,
1496                                                      K3b::Device::STATE_COMPLETE,
1497                                                      K3b::Medium::ContentVideoCD,
1498                                                      this,
1499                                                      i18n("Video CD Rip") );
1500 
1501     if( dev )
1502         d->dirView->showDevice( dev );
1503 }
1504 
1505 
1506 void K3b::MainWindow::slotVideoCdRip()
1507 {
1508     videoCdRip( 0 );
1509 }
1510 
1511 
1512 void K3b::MainWindow::showDiskInfo( K3b::Device::Device* dev )
1513 {
1514     d->dirView->showDiskInfo( dev );
1515 }
1516 
1517 #include "moc_k3b.cpp"