File indexing completed on 2024-10-06 04:25:57
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"