File indexing completed on 2024-04-28 17:00:47

0001 /***************************************************************************
0002  *   Copyright (C) 2005-2009 by Rajko Albrecht                             *
0003  *   ral@alwins-world.de                                                   *
0004  *                                                                         *
0005  *   This program is free software; you can redistribute it and/or modify  *
0006  *   it under the terms of the GNU General Public License as published by  *
0007  *   the Free Software Foundation; either version 2 of the License, or     *
0008  *   (at your option) any later version.                                   *
0009  *                                                                         *
0010  *   This program is distributed in the hope that it will be useful,       *
0011  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
0012  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
0013  *   GNU General Public License for more details.                          *
0014  *                                                                         *
0015  *   You should have received a copy of the GNU General Public License     *
0016  *   along with this program; if not, write to the                         *
0017  *   Free Software Foundation, Inc.,                                       *
0018  *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.         *
0019  ***************************************************************************/
0020 
0021 #include "kdesvn.h"
0022 #include "urldlg.h"
0023 #include "kdesvn_part.h"
0024 #include "helpers/ktranslateurl.h"
0025 #include "helpers/kdesvn_debug.h"
0026 
0027 #include <QApplication>
0028 #include <QDir>
0029 #include <QMenuBar>
0030 #include <QStatusBar>
0031 #include <QTimer>
0032 
0033 #include <ksharedconfig.h>
0034 #include <kconfig.h>
0035 #include <kconfiggroup.h>
0036 #include <khelpmenu.h>
0037 #include <KActionCollection>
0038 #include <KBookmarkManager>
0039 #include <KLocalizedString>
0040 #include <KMessageBox>
0041 #include <KPluginFactory>
0042 #include <KPluginLoader>
0043 #include <KRecentFilesAction>
0044 #include <KStandardAction>
0045 #include <KToggleAction>
0046 #include <KEditToolBar>
0047 #include <KShortcutsDialog>
0048 
0049 #ifdef TESTING_RC
0050 #include <kcrash.h>
0051 #endif
0052 
0053 kdesvn::kdesvn()
0054     : KParts::MainWindow(),
0055       KBookmarkOwner()
0056 {
0057     setAttribute(Qt::WA_DeleteOnClose);
0058     m_part = nullptr;
0059 #ifdef TESTING_RC
0060     setXMLFile(TESTING_RC);
0061     qCDebug(KDESVN_LOG) << "Using test rc file in " << TESTING_RC << endl;
0062     // I hate this crashhandler in development
0063     KCrash::setCrashHandler(0);
0064 #else
0065     setXMLFile(QStringLiteral("kdesvnui.rc"));
0066 #endif
0067     setStandardToolBarMenuEnabled(true);
0068     // then, setup our actions
0069     setupActions();
0070     // and a status bar
0071     statusBar()->show();
0072 
0073     QDir bookmarkDir(QStandardPaths::writableLocation(QStandardPaths::DataLocation));
0074     if (!bookmarkDir.exists()) {
0075         bookmarkDir.mkpath(bookmarkDir.absolutePath());
0076     }
0077 
0078     m_bookmarkFile = bookmarkDir.absolutePath()+ QLatin1String("/bookmarks.xml");
0079     m_BookmarkManager = KBookmarkManager::managerForExternalFile(m_bookmarkFile);
0080     m_BookmarksActionmenu = new KBookmarkActionMenu(m_BookmarkManager->root(),
0081                                                     i18n("&Bookmarks"), this);
0082 
0083     actionCollection()->addAction(QStringLiteral("bookmarks"), m_BookmarksActionmenu);
0084     m_Bookmarkactions = new KActionCollection(static_cast<QWidget *>(this));
0085     m_pBookmarkMenu = new KBookmarkMenu(m_BookmarkManager, this, m_BookmarksActionmenu->menu(), m_Bookmarkactions);
0086     m_pBookmarkMenu->setParent(this); // clear when kdesvn window gets destroyed
0087 
0088 #ifdef EXTRA_KDE_LIBPATH
0089     QCoreApplication::addLibraryPath(QString::fromLocal8Bit(EXTRA_KDE_LIBPATH))
0090 #endif
0091     // this routine will find and load our Part.  it finds the Part by
0092     // name which is a bad idea usually.. but it's alright in this
0093     // case since our Part is made for this Shell
0094     KPluginLoader loader(QStringLiteral("kdesvnpart"));
0095     KPluginFactory *factory = loader.factory();
0096     if (factory) {
0097         m_part = factory->create<KParts::ReadOnlyPart>(this);
0098         if (m_part) {
0099             // tell the KParts::MainWindow that this is indeed the main widget
0100             setCentralWidget(m_part->widget());
0101             connect(this, SIGNAL(sigSavestate()), m_part->widget(), SLOT(slotSavestate()));
0102             connect(m_part->widget(), SIGNAL(sigExtraStatusMessage(QString)), this, SLOT(slotExtraStatus(QString)));
0103             connect(m_part->widget(), SIGNAL(sigUrlOpened(bool)), this, SLOT(slotUrlOpened(bool)));
0104 
0105             QAction *tmpAction;
0106             tmpAction = actionCollection()->addAction(QStringLiteral("subversion_create_repo"),
0107                                                       m_part->widget(),
0108                                                       SLOT(slotCreateRepo()));
0109             tmpAction->setText(i18n("Create and open new repository"));
0110             tmpAction->setToolTip(i18n("Create and opens a new local Subversion repository"));
0111 
0112             tmpAction = actionCollection()->addAction(QStringLiteral("subversion_dump_repo"),
0113                                                       m_part->widget(),
0114                                                       SLOT(slotDumpRepo()));
0115             tmpAction->setText(i18n("Dump repository to file"));
0116             tmpAction->setToolTip(i18n("Dump a Subversion repository to a file"));
0117 
0118             tmpAction = actionCollection()->addAction(QStringLiteral("subversion_hotcopy_repo"),
0119                                                       m_part->widget(),
0120                                                       SLOT(slotHotcopy()));
0121             tmpAction->setText(i18n("Hotcopy a repository"));
0122             tmpAction->setToolTip(i18n("Hotcopy a Subversion repository to a new folder"));
0123 
0124             tmpAction = actionCollection()->addAction(QStringLiteral("subversion_load_repo"),
0125                                                       m_part->widget(),
0126                                                       SLOT(slotLoaddump()));
0127             tmpAction->setText(i18n("Load dump into repository"));
0128             tmpAction->setToolTip(i18n("Load a dump file into a repository."));
0129 
0130             tmpAction = actionCollection()->addAction(QStringLiteral("kdesvn_ssh_add"),
0131                                                       m_part,
0132                                                       SLOT(slotSshAdd()));
0133             tmpAction->setText(i18n("Add ssh identities to ssh-agent"));
0134             tmpAction->setToolTip(i18n("Force add ssh-identities to ssh-agent for future use."));
0135 
0136             tmpAction = actionCollection()->addAction(QStringLiteral("help_about_kdesvnpart"),
0137                                                       m_part,
0138                                                       SLOT(showAboutApplication()));
0139             tmpAction->setText(i18n("Info about kdesvn part"));
0140             tmpAction->setToolTip(i18n("Shows info about the kdesvn plugin and not the standalone application."));
0141 
0142             tmpAction = actionCollection()->addAction(QStringLiteral("db_show_status"),
0143                                                       m_part,
0144                                                       SLOT(showDbStatus()));
0145             tmpAction->setText(i18n("Show database content"));
0146             tmpAction->setToolTip(i18n("Show the content of log cache database"));
0147 
0148             // and integrate the part's GUI with the shells
0149             createGUI(m_part);
0150 
0151         } else {
0152             KMessageBox::error(this, i18n("Could not load the part:\n%1", loader.errorString()));
0153             qApp->quit();
0154             return;
0155         }
0156     } else {
0157         // if we couldn't find our Part, we exit since the Shell by
0158         // itself can't do anything useful
0159         KMessageBox::error(this, i18n("Could not find our part:\n%1", loader.errorString()));
0160         qApp->quit();
0161         // we return here, cause kapp->quit() only means "exit the
0162         // next time we enter the event loop...
0163         return;
0164     }
0165     setAutoSaveSettings();
0166 }
0167 
0168 kdesvn::~kdesvn()
0169 {
0170 }
0171 
0172 void kdesvn::loadRescent(const QUrl &url)
0173 {
0174     load(url, true);
0175 }
0176 
0177 void kdesvn::load(const QUrl &url, bool addRescent)
0178 {
0179     QTimer::singleShot(100, this, &kdesvn::slotResetExtraStatus);
0180     if (m_part) {
0181         bool ret = m_part->openUrl(url);
0182         KRecentFilesAction *rac = nullptr;
0183         if (addRescent) {
0184             QAction *ac = actionCollection()->action(QStringLiteral("file_open_recent"));
0185             if (ac) {
0186                 rac = (KRecentFilesAction *)ac;
0187             }
0188         }
0189         if (!ret) {
0190             changeStatusbar(i18n("Could not open URL %1", url.toString()));
0191             if (rac) {
0192                 rac->removeUrl(url);
0193             }
0194         } else {
0195             resetStatusBar();
0196             if (rac) {
0197                 rac->addUrl(url);
0198             }
0199         }
0200         if (rac) {
0201             KConfigGroup cg(KSharedConfig::openConfig(), "recent_files");
0202             rac->saveEntries(cg);
0203         }
0204     }
0205 }
0206 
0207 void kdesvn::setupActions()
0208 {
0209     QAction *ac;
0210     KStandardAction::open(this, SLOT(fileOpen()), actionCollection());
0211     KStandardAction::openNew(this, SLOT(fileNew()), actionCollection());
0212     ac = KStandardAction::close(this, SLOT(fileClose()), actionCollection());
0213 //     ac->setEnabled(getMemberList()->count()>1);
0214     ac->setEnabled(memberList().count() > 1);
0215     KStandardAction::quit(this, SLOT(close()), actionCollection());
0216 
0217     KRecentFilesAction *rac = KStandardAction::openRecent(this, SLOT(loadRescent(QUrl)), actionCollection());
0218     if (rac) {
0219         rac->setMaxItems(8);
0220         KConfigGroup cg(KSharedConfig::openConfig(), "recent_files");
0221         rac->loadEntries(cg);
0222         rac->setText(i18n("Recent opened URLs"));
0223     }
0224 
0225     KStandardAction::keyBindings(this, SLOT(optionsConfigureKeys()), actionCollection());
0226     KStandardAction::configureToolbars(this, SLOT(optionsConfigureToolbars()), actionCollection());
0227 
0228     m_statusbarAction = KStandardAction::showStatusbar(this, SLOT(optionsShowStatusbar()), actionCollection());
0229 
0230     KToggleAction *toggletemp;
0231     toggletemp = new KToggleAction(i18n("Load last opened URL on start"), this);
0232     actionCollection()->addAction(QStringLiteral("toggle_load_last_url"), toggletemp);
0233     toggletemp->setToolTip(i18n("Reload last opened URL if no one is given on command line"));
0234     KConfigGroup cs(KSharedConfig::openConfig(), "startup");
0235     toggletemp->setChecked(cs.readEntry("load_last_on_start", false));
0236     connect(toggletemp, &QAction::toggled, this, &kdesvn::slotLoadLast);
0237 }
0238 
0239 void kdesvn::optionsShowStatusbar()
0240 {
0241     // this is all very cut and paste code for showing/hiding the
0242     // statusbar
0243     statusBar()->setVisible(m_statusbarAction->isChecked());
0244 }
0245 
0246 void kdesvn::fileClose()
0247 {
0248     if (m_part) {
0249         m_part->closeUrl();
0250     }
0251 //     if (getMemberList()->count()>1) {
0252     if (memberList().count() > 1) {
0253         close();
0254     } else {
0255         enableClose(false);
0256         QTimer::singleShot(100, this, &kdesvn::slotResetExtraStatus);
0257         enableClose(false);
0258     }
0259 }
0260 
0261 void kdesvn::saveProperties(KConfigGroup &config)
0262 {
0263     // the 'config' object points to the session managed
0264     // config file.  anything you write here will be available
0265     // later when this app is restored
0266     if (!m_part) {
0267         return;
0268     }
0269     if (!m_part->url().isEmpty()) {
0270         config.writeEntry("lastURL", m_part->url().toString());
0271     }
0272 }
0273 
0274 void kdesvn::readProperties(const KConfigGroup &config)
0275 {
0276     // the 'config' object points to the session managed
0277     // config file.  this function is automatically called whenever
0278     // the app is being restored.  read in here whatever you wrote
0279     // in 'saveProperties'
0280     if (!m_part) {
0281         return;
0282     }
0283 
0284     const QUrl url(config.readPathEntry("lastURL", QString()));
0285     if (url.isValid()) {
0286         m_part->openUrl(url);
0287     }
0288 }
0289 
0290 void kdesvn::fileNew()
0291 {
0292     // this slot is called whenever the File->New menu is selected,
0293     // the New shortcut is pressed (usually CTRL+N) or the New toolbar
0294     // button is clicked
0295 
0296     // create a new window
0297     (new kdesvn)->show();
0298     enableClose(true);
0299 }
0300 
0301 void kdesvn::fileOpen()
0302 {
0303     QUrl url = UrlDlg::getUrl(this);
0304     if (!url.isEmpty()) {
0305         load(url, true);
0306     }
0307 }
0308 
0309 void kdesvn::changeStatusbar(const QString &text)
0310 {
0311     statusBar()->showMessage(text);
0312 }
0313 
0314 void kdesvn::resetStatusBar()
0315 {
0316     statusBar()->showMessage(i18n("Ready"), 4000);
0317 }
0318 
0319 // kde4 port - pv
0320 void kdesvn::openBookmark(const KBookmark &bm, Qt::MouseButtons mb, Qt::KeyboardModifiers km)
0321 {
0322     Q_UNUSED(mb);
0323     Q_UNUSED(km);
0324     if (!bm.url().isEmpty() && m_part) {
0325         load(bm.url(), false);
0326     }
0327 }
0328 
0329 QUrl kdesvn::currentUrl() const
0330 {
0331     if (!m_part) {
0332         return QUrl();
0333     }
0334     return m_part->url();
0335 }
0336 
0337 QString kdesvn::currentTitle() const
0338 {
0339     if (!m_part) {
0340         return QString();
0341     }
0342     return m_part->url().fileName();
0343 }
0344 
0345 void kdesvn::enableClose(bool how)
0346 {
0347     QAction *ac;
0348     if ((ac = actionCollection()->action(QStringLiteral("file_close")))) {
0349         ac->setEnabled(how);
0350     }
0351 }
0352 
0353 /*!
0354     \fn kdesvn::slotUrlOpened(bool)
0355  */
0356 void kdesvn::slotUrlOpened(bool how)
0357 {
0358     enableClose(how);
0359 }
0360 
0361 /*!
0362     \fn kdesvn::optionsConfigureToolbars()
0363  */
0364 void kdesvn::optionsConfigureToolbars()
0365 {
0366     KConfigGroup cg(KSharedConfig::openConfig(), autoSaveGroup());
0367     saveMainWindowSettings(cg);
0368 
0369     // use the standard toolbar editor
0370     QPointer<KEditToolBar> dlg(new KEditToolBar(factory()));
0371     connect(dlg.data(), &KEditToolBar::newToolbarConfig,
0372             this, &kdesvn::applyNewToolbarConfig);
0373     dlg->exec();
0374     delete dlg;
0375 }
0376 
0377 /*!
0378     \fn kdesvn::applyNewToolbarConfig()
0379  */
0380 void kdesvn::applyNewToolbarConfig()
0381 {
0382     KConfigGroup cg(KSharedConfig::openConfig(), autoSaveGroup());
0383     applyMainWindowSettings(cg);
0384 }
0385 
0386 void kdesvn::optionsConfigureKeys()
0387 {
0388     QPointer<KShortcutsDialog> kdlg(new KShortcutsDialog(KShortcutsEditor::AllActions,
0389                                                          KShortcutsEditor::LetterShortcutsAllowed,
0390                                                          m_part->widget()));
0391     kdlg->addCollection(actionCollection());
0392     kdlg->addCollection(m_part->actionCollection());
0393 
0394     kdlg->configure(true);
0395     delete kdlg;
0396 }
0397 
0398 /*!
0399     \fn kdesvn::closeEvent()
0400  */
0401 void kdesvn::closeEvent(QCloseEvent *ev)
0402 {
0403     emit sigSavestate();
0404     if (m_part) {
0405         KConfigGroup cs(KSharedConfig::openConfig(), "startup");
0406         cs.writeEntry("lastURL", m_part->url().toString(QUrl::FullyEncoded));
0407         cs.sync();
0408     }
0409     return KParts::MainWindow::closeEvent(ev);
0410 }
0411 
0412 /*!
0413     \fn kdesvn::checkReload()
0414  */
0415 void kdesvn::checkReload()
0416 {
0417     KConfigGroup cs(KSharedConfig::openConfig(), "startup");
0418     if (!cs.readEntry("load_last_on_start", false)) {
0419         return;
0420     }
0421 
0422     const QUrl url(cs.readPathEntry("lastURL", QString()));
0423     if (url.isValid() && m_part) {
0424         load(url, false);
0425     }
0426 }
0427 
0428 /*!
0429     \fn kdesvn::slotLoadLast(bool)
0430  */
0431 void kdesvn::slotLoadLast(bool how)
0432 {
0433     KConfigGroup cs(KSharedConfig::openConfig(), "startup");
0434     cs.writeEntry("load_last_on_start", how);
0435     cs.sync();
0436 }
0437 
0438 void kdesvn::slotResetExtraStatus()
0439 {
0440     statusBar()->clearMessage();
0441 }
0442 
0443 void kdesvn::slotExtraStatus(const QString &message)
0444 {
0445     statusBar()->clearMessage();
0446     statusBar()->showMessage(message);
0447 }