summaryrefslogtreecommitdiffstats
path: root/src/svnfrontend/svnactions.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/svnfrontend/svnactions.cpp')
-rw-r--r--src/svnfrontend/svnactions.cpp2891
1 files changed, 2891 insertions, 0 deletions
diff --git a/src/svnfrontend/svnactions.cpp b/src/svnfrontend/svnactions.cpp
new file mode 100644
index 0000000..082666f
--- /dev/null
+++ b/src/svnfrontend/svnactions.cpp
@@ -0,0 +1,2891 @@
+/***************************************************************************
+ * Copyright (C) 2005-2007 by Rajko Albrecht *
+ * ral@alwins-world.de *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
+ ***************************************************************************/
+#include "svnactions.h"
+#include "checkoutinfo_impl.h"
+#include "itemdisplay.h"
+#include "svnitem.h"
+#include "rangeinput_impl.h"
+#include "propertiesdlg.h"
+#include "ccontextlistener.h"
+#include "tcontextlistener.h"
+#include "modifiedthread.h"
+#include "fillcachethread.h"
+#include "svnlogdlgimp.h"
+#include "stopdlg.h"
+#include "blamedisplay_impl.h"
+#include "src/ksvnwidgets/logmsg_impl.h"
+#include "src/ksvnwidgets/diffbrowser.h"
+#include "src/ksvnwidgets/encodingselector_impl.h"
+#include "src/ksvnwidgets/revertform_impl.h"
+#include "graphtree/revisiontree.h"
+#include "src/settings/kdesvnsettings.h"
+#include "src/kdesvn_events.h"
+#include "src/svnqt/client.hpp"
+#include "src/svnqt/annotate_line.hpp"
+#include "src/svnqt/context_listener.hpp"
+#include "src/svnqt/dirent.hpp"
+#include "src/svnqt/targets.hpp"
+#include "src/svnqt/url.hpp"
+#include "src/svnqt/wc.hpp"
+#include "src/svnqt/svnqt_defines.hpp"
+#include "src/svnqt/cache/LogCache.hpp"
+#include "src/svnqt/cache/ReposLog.hpp"
+#include "src/svnqt/url.hpp"
+
+#include "helpers/sub2qt.h"
+#include "fronthelpers/cursorstack.h"
+#include "cacheentry.h"
+
+#include <kdialog.h>
+#include <ktextbrowser.h>
+#include <klocale.h>
+#include <kglobalsettings.h>
+#include <kmessagebox.h>
+#include <kinputdialog.h>
+#include <kprocess.h>
+#include <ktempdir.h>
+#include <ktempfile.h>
+#include <kdialogbase.h>
+#include <kapplication.h>
+#include <kio/jobclasses.h>
+#include <kio/job.h>
+#include <kdebug.h>
+#include <kconfig.h>
+#include <klistview.h>
+#include <kio/netaccess.h>
+#include <kstandarddirs.h>
+#include <ktrader.h>
+#include <krun.h>
+#include <kstdguiitem.h>
+
+#include <qstring.h>
+#include <qmap.h>
+#include <qpushbutton.h>
+#include <qlayout.h>
+#include <qvaluelist.h>
+#include <qvbox.h>
+#include <qstylesheet.h>
+#include <qregexp.h>
+#include <qimage.h>
+#include <qthread.h>
+#include <qtimer.h>
+#include <qlistview.h>
+#include <qfileinfo.h>
+#include <sys/time.h>
+#include <unistd.h>
+#include <qguardedptr.h>
+
+// wait not longer than 10 seconds for a thread
+#define MAX_THREAD_WAITTIME 10000
+
+class SvnActionsData:public svn::ref_count
+{
+ typedef svn::SharedPointer<svn::PathPropertiesMapList> sPPlist;
+public:
+ SvnActionsData():ref_count()
+ {
+ m_Svnclient = svn::Client::getobject(0,0);
+ m_CurrentContext = 0;
+ }
+
+ virtual ~SvnActionsData()
+ {
+ if (m_DiffDialog) {
+ m_DiffDialog->saveDialogSize(*(Kdesvnsettings::self()->config()),"diff_display",false);
+ delete m_DiffDialog;
+ }
+ if (m_LogDialog) {
+ m_LogDialog->saveSize();
+ delete m_LogDialog;
+ }
+
+ QMap<KProcess*,QStringList>::iterator it;
+ for (it=m_tempfilelist.begin();it!=m_tempfilelist.end();++it) {
+ for (QStringList::iterator it2 = (*it).begin();
+ it2 != (*it).end();++it2) {
+ ::unlink((*it2).ascii());
+ }
+ }
+ for (it=m_tempdirlist.begin();it!=m_tempdirlist.end();++it) {
+ for (QStringList::iterator it2 = (*it).begin();
+ it2 != (*it).end();++it2) {
+ KIO::NetAccess::del((*it2),0);
+ }
+ }
+ delete m_Svnclient;
+ m_Svnclient = 0L;
+ }
+
+ bool isExternalDiff()
+ {
+ if (Kdesvnsettings::use_external_diff()) {
+ QString edisp = Kdesvnsettings::external_diff_display();
+ QStringList wlist = QStringList::split(" ",edisp);
+ if (wlist.count()>=3 && edisp.find("%1")!=-1 && edisp.find("%2")!=-1) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ void clearCaches()
+ {
+ m_PropertiesCache.clear();
+ m_contextData.clear();
+ m_InfoCache.clear();
+ }
+
+ void cleanDialogs()
+ {
+ if (m_DiffDialog) {
+ m_DiffDialog->saveDialogSize(*(Kdesvnsettings::self()->config()),"diff_display",false);
+ delete m_DiffDialog;
+ m_DiffDialog=0;
+ }
+ if (m_LogDialog) {
+ m_LogDialog->saveSize();
+ delete m_LogDialog;
+ m_LogDialog=0;
+ }
+ }
+
+ ItemDisplay* m_ParentList;
+
+ svn::smart_pointer<CContextListener> m_SvnContextListener;
+ svn::ContextP m_CurrentContext;
+ svn::Client*m_Svnclient;
+
+ helpers::statusCache m_UpdateCache;
+ helpers::statusCache m_Cache;
+ helpers::statusCache m_conflictCache;
+ helpers::statusCache m_repoLockCache;
+ helpers::itemCache<svn::PathPropertiesMapListPtr> m_PropertiesCache;
+ /// \todo as persistent cache (sqlite?)
+ helpers::itemCache<svn::InfoEntry> m_InfoCache;
+
+ QMap<KProcess*,QStringList> m_tempfilelist;
+ QMap<KProcess*,QStringList> m_tempdirlist;
+
+ QTimer m_ThreadCheckTimer;
+ QTimer m_UpdateCheckTimer;
+ QTime m_UpdateCheckTick;
+ QGuardedPtr<DiffBrowser> m_DiffBrowserPtr;
+ QGuardedPtr<KDialogBase> m_DiffDialog;
+ QGuardedPtr<SvnLogDlgImp> m_LogDialog;
+
+ QMap<QString,QString> m_contextData;
+
+ bool runblocked;
+};
+
+#define EMIT_FINISHED emit sendNotify(i18n("Finished"))
+#define EMIT_REFRESH emit sigRefreshAll()
+#define DIALOGS_SIZES "display_dialogs_sizes"
+
+SvnActions::SvnActions(ItemDisplay *parent, const char *name,bool processes_blocked)
+ : QObject(parent?parent->realWidget():0, name),SimpleLogCb()
+{
+ m_CThread = 0;
+ m_UThread = 0;
+ m_FCThread = 0;
+ m_Data = new SvnActionsData();
+ m_Data->m_ParentList = parent;
+ m_Data->m_SvnContextListener = new CContextListener(this);
+ m_Data->runblocked = processes_blocked;
+ connect(m_Data->m_SvnContextListener,SIGNAL(sendNotify(const QString&)),this,SLOT(slotNotifyMessage(const QString&)));
+ connect(&(m_Data->m_ThreadCheckTimer),SIGNAL(timeout()),this,SLOT(checkModthread()));
+ connect(&(m_Data->m_UpdateCheckTimer),SIGNAL(timeout()),this,SLOT(checkUpdateThread()));
+}
+
+svn::Client* SvnActions::svnclient()
+{
+ return m_Data->m_Svnclient;
+}
+
+SvnActions::~SvnActions()
+{
+ killallThreads();
+}
+
+void SvnActions::slotNotifyMessage(const QString&aMsg)
+{
+ emit sendNotify(aMsg);
+}
+
+void SvnActions::reInitClient()
+{
+ m_Data->clearCaches();
+ m_Data->cleanDialogs();
+ if (m_Data->m_CurrentContext) m_Data->m_CurrentContext->setListener(0L);
+ m_Data->m_CurrentContext = new svn::Context();
+ m_Data->m_CurrentContext->setListener(m_Data->m_SvnContextListener);
+ m_Data->m_Svnclient->setContext(m_Data->m_CurrentContext);
+}
+
+template<class T> KDialogBase* SvnActions::createDialog(T**ptr,const QString&_head,bool OkCancel,const char*name,bool showHelp,bool modal,const KGuiItem&u1)
+{
+ int buttons = KDialogBase::Ok;
+ if (OkCancel) {
+ buttons = buttons|KDialogBase::Cancel;
+ }
+ if (showHelp) {
+ buttons = buttons|KDialogBase::Help;
+ }
+ if (!u1.text().isEmpty()) {
+ buttons = buttons|KDialogBase::User1;
+ }
+ KDialogBase * dlg = new KDialogBase(
+ modal?KApplication::activeModalWidget():0, // parent
+ name, // name
+ modal, // modal
+ _head, // caption
+ buttons, // buttonmask
+ KDialogBase::Ok, // defaultButton
+ false , // separator
+ (u1.text().isEmpty()?KGuiItem():u1) //user1
+ );
+
+ if (!dlg) return dlg;
+ QWidget* Dialog1Layout = dlg->makeVBoxMainWidget();
+ *ptr = new T(Dialog1Layout);
+ dlg->resize(dlg->configDialogSize(*(Kdesvnsettings::self()->config()),name?name:DIALOGS_SIZES));
+ return dlg;
+}
+
+/*!
+ \fn SvnActions::makeLog(svn::Revision start,svn::Revision end,FileListViewItem*k)
+ */
+void SvnActions::makeLog(const svn::Revision&start,const svn::Revision&end,const svn::Revision&peg,SvnItem*k,bool list_files,int limit)
+{
+ if (k) {
+ makeLog(start,end,peg,k->fullName(),list_files,limit);
+ }
+}
+
+svn::SharedPointer<svn::LogEntriesMap> SvnActions::getLog(const svn::Revision&start,const svn::Revision&end,const svn::Revision&peg,const QString&which,bool list_files,
+ int limit,QWidget*parent)
+{
+ svn::SharedPointer<svn::LogEntriesMap> logs = new svn::LogEntriesMap;
+ if (!m_Data->m_CurrentContext) return 0;
+
+ bool follow = Kdesvnsettings::log_follows_nodes();
+
+ kdDebug()<<"Get logs for "<< which<<endl;
+ try {
+ StopDlg sdlg(m_Data->m_SvnContextListener,(parent?parent:m_Data->m_ParentList->realWidget()),0,"Logs",
+ i18n("Getting logs - hit cancel for abort"));
+ connect(this,SIGNAL(sigExtraLogMsg(const QString&)),&sdlg,SLOT(slotExtraMessage(const QString&)));
+ if (doNetworking()) {
+ m_Data->m_Svnclient->log(which,start,end,*logs,peg,list_files,!follow,limit);
+ } else {
+ svn::InfoEntry e;
+ if (!singleInfo(m_Data->m_ParentList->baseUri(),svn::Revision::BASE,e)) {
+ return 0;
+ }
+ if (svn::Url::isLocal(e.reposRoot())) {
+ m_Data->m_Svnclient->log(which,start,end,*logs,peg,list_files,!follow,limit);
+ } else {
+ svn::cache::ReposLog rl(m_Data->m_Svnclient,e.reposRoot());
+ QString s1,s2,what;
+ s1=e.url().mid(e.reposRoot().length());
+ if (which==".") {
+ what=s1;
+ } else {
+ s2=which.mid(m_Data->m_ParentList->baseUri().length());
+ what=s1+"/"+s2;
+ }
+ rl.log(what,start,end,peg,*logs,!follow,limit);
+ }
+ }
+ } catch (const svn::Exception&e) {
+ emit clientException(e.msg());
+ return 0;
+ }
+ if (!logs) {
+ emit clientException(i18n("Got no logs"));
+ return 0;
+ }
+ return logs;
+}
+
+bool SvnActions::getSingleLog(svn::LogEntry&t,const svn::Revision&r,const QString&what,const svn::Revision&peg,QString&root)
+{
+ bool res = false;
+
+ if (what.isEmpty()) {
+ return res;
+ }
+ if (root.isEmpty()) {
+ svn::InfoEntry inf;
+ if (!singleInfo(what,peg,inf))
+ {
+ return res;
+ }
+ root = inf.reposRoot();
+ }
+
+ if (!svn::Url::isLocal(root)) {
+ svn::LogEntriesMap _m;
+ try {
+ svn::cache::ReposLog rl(m_Data->m_Svnclient ,root);
+ if (rl.isValid() && rl.simpleLog(_m,r,r,true) && _m.find(r.revnum())!=_m.end() ) {
+ t = _m[r.revnum()];
+ res = true;
+ }
+ } catch (const svn::Exception&e) {
+ emit clientException(e.msg());
+ }
+ }
+
+ if (!res) {
+ svn::SharedPointer<svn::LogEntriesMap> log = getLog(r,r,peg,root,true,1);
+ if (log) {
+ if (log->find(r.revnum())!=log->end()) {
+ t = (*log)[r.revnum()];
+ res = true;
+ }
+ }
+ }
+ return res;
+}
+
+bool SvnActions::singleInfo(const QString&what,const svn::Revision&_rev,svn::InfoEntry&target,const svn::Revision&_peg)
+{
+ QString url;
+ QString ex;
+ QString cacheKey;
+ QTime d; d.start();
+ svn::Revision rev = _rev;
+ svn::Revision peg = _peg;
+ if (!m_Data->m_CurrentContext) return false;
+ if (!svn::Url::isValid(what)) {
+ // working copy
+ // url = svn::Wc::getUrl(what);
+ url = what;
+ if (url.find("@")!=-1) {
+ url+="@BASE";
+ }
+ peg = svn::Revision::UNDEFINED;
+ cacheKey=url;
+ } else {
+ KURL _uri = what;
+ QString prot = svn::Url::transformProtokoll(_uri.protocol());
+ _uri.setProtocol(prot);
+ url = _uri.prettyURL();
+ if (peg==svn::Revision::UNDEFINED)
+ {
+ peg = _rev;
+ }
+ if (peg==svn::Revision::UNDEFINED)
+ {
+ peg=svn::Revision::HEAD;
+ }
+ cacheKey=_rev.toString()+"/"+url;
+ }
+ svn::InfoEntries e;
+
+ if (cacheKey.isEmpty() || !m_Data->m_InfoCache.findSingleValid(cacheKey,target)) {
+ try {
+ e = (m_Data->m_Svnclient->info(url,svn::DepthEmpty,_rev,peg));
+ } catch (const svn::Exception&ce) {
+ kdDebug()<<"Singleinfo: "<<_rev.toString()<<endl;
+ kdDebug()<<"Singleinfo: "<<ce.msg() << endl;
+ emit clientException(ce.msg());
+ return false;
+ }
+ if (e.count()<1||e[0].reposRoot().isEmpty()) {
+ emit clientException(i18n("Got no info."));
+ return false;
+ }
+ target = e[0];
+ if (!cacheKey.isEmpty()) {
+ m_Data->m_InfoCache.insertKey(e[0],cacheKey);
+ if (peg != svn::Revision::UNDEFINED && peg.kind()!= svn::Revision::NUMBER && peg.kind()!= svn::Revision::DATE ) {
+ // for persistent storage, store head into persistent cache makes no sense.
+ cacheKey=e[0].revision().toString()+"/"+url;
+ kdDebug()<<"Extra: "<<cacheKey<<endl;
+ m_Data->m_InfoCache.insertKey(e[0],cacheKey);
+ }
+ }
+ }
+ return true;
+}
+
+void SvnActions::makeTree(const QString&what,const svn::Revision&_rev,const svn::Revision&startr,const svn::Revision&endr)
+{
+ svn::InfoEntry info;
+ if (!singleInfo(what,_rev,info)) {
+ return;
+ }
+ QString reposRoot = info.reposRoot();
+
+ bool restartCache = (m_FCThread && m_FCThread->running());
+ if (restartCache) {
+ stopFillCache();
+ }
+ kdDebug()<<"Logs for "<<reposRoot<<endl;
+ QWidget*disp;
+ KDialogBase dlg(m_Data->m_ParentList->realWidget(),"historylist",true,i18n("History of %1").arg(info.url().mid(reposRoot.length())),
+ KDialogBase::Ok,
+ KDialogBase::Ok,true);
+ QWidget* Dialog1Layout = dlg.makeVBoxMainWidget();
+
+ RevisionTree rt(m_Data->m_Svnclient,m_Data->m_SvnContextListener,reposRoot,
+ startr,endr,
+ info.prettyUrl().mid(reposRoot.length()),_rev,Dialog1Layout,m_Data->m_ParentList->realWidget());
+ if (rt.isValid()) {
+ disp = rt.getView();
+ if (disp) {
+ connect(
+ disp,SIGNAL(makeNorecDiff(const QString&,const svn::Revision&,const QString&,const svn::Revision&,QWidget*)),
+ this,SLOT(makeNorecDiff(const QString&,const svn::Revision&,const QString&,const svn::Revision&,QWidget*))
+ );
+ connect(
+ disp,SIGNAL(makeRecDiff(const QString&,const svn::Revision&,const QString&,const svn::Revision&,QWidget*)),
+ this,SLOT(makeDiff(const QString&,const svn::Revision&,const QString&,const svn::Revision&,QWidget*))
+ );
+ connect(disp,SIGNAL(makeCat(const svn::Revision&, const QString&,const QString&,const svn::Revision&,QWidget*)),
+ this,SLOT(slotMakeCat(const svn::Revision&,const QString&,const QString&,const svn::Revision&,QWidget*)));
+ dlg.resize(dlg.configDialogSize(*(Kdesvnsettings::self()->config()),"revisiontree_dlg"));
+ dlg.exec();
+ dlg.saveDialogSize(*(Kdesvnsettings::self()->config()),"revisiontree_dlg",false);
+ }
+ }
+ if (restartCache) {
+ startFillCache(reposRoot);
+ }
+}
+
+void SvnActions::makeLog(const svn::Revision&start,const svn::Revision&end,const svn::Revision&peg,const QString&which,bool list_files,int limit)
+{
+ svn::InfoEntry info;
+ if (!singleInfo(which,start,info)) {
+ return;
+ }
+ QString reposRoot = info.reposRoot();
+ kdDebug()<<"getting logs..."<<endl;
+ svn::SharedPointer<svn::LogEntriesMap> logs = getLog(start,end,peg,which,list_files,limit);
+ if (!logs) return;
+ bool need_modal = m_Data->runblocked||KApplication::activeModalWidget()!=0;
+ if (need_modal||!m_Data->m_LogDialog) {
+ m_Data->m_LogDialog=new SvnLogDlgImp(this,0,"logdialog",need_modal);
+ connect(m_Data->m_LogDialog,SIGNAL(makeDiff(const QString&,const svn::Revision&,const QString&,const svn::Revision&,QWidget*)),
+ this,SLOT(makeDiff(const QString&,const svn::Revision&,const QString&,const svn::Revision&,QWidget*)));
+ connect(m_Data->m_LogDialog,SIGNAL(makeCat(const svn::Revision&, const QString&,const QString&,const svn::Revision&,QWidget*)),
+ this,SLOT(slotMakeCat(const svn::Revision&,const QString&,const QString&,const svn::Revision&,QWidget*)));
+ }
+
+ if (m_Data->m_LogDialog) {
+ m_Data->m_LogDialog->dispLog(logs,info.url().mid(reposRoot.length()),reposRoot,
+ (
+ peg==svn::Revision::UNDEFINED?
+ (svn::Url::isValid(which)?svn::Revision::HEAD:svn::Revision::UNDEFINED):
+ peg
+ ),which);
+ if (need_modal) {
+ m_Data->m_LogDialog->exec();
+ m_Data->m_LogDialog->saveSize();
+ delete m_Data->m_LogDialog;
+ } else {
+ m_Data->m_LogDialog->show();
+ m_Data->m_LogDialog->raise();
+ }
+ }
+ EMIT_FINISHED;
+}
+
+void SvnActions::makeBlame(const svn::Revision&start, const svn::Revision&end, SvnItem*k)
+{
+ if (k) makeBlame(start,end,k->fullName(),m_Data->m_ParentList->realWidget());
+}
+
+void SvnActions::makeBlame(const svn::Revision&start, const svn::Revision&end,const QString&k,QWidget*_p,const svn::Revision&_peg,SimpleLogCb*_acb)
+{
+ if (!m_Data->m_CurrentContext) return;
+ svn::AnnotatedFile blame;
+ QString ex;
+ svn::Path p(k);
+ QWidget*_parent = _p?_p:m_Data->m_ParentList->realWidget();
+ svn::Revision peg = _peg==svn::Revision::UNDEFINED?end:_peg;
+
+ try {
+ CursorStack a(Qt::BusyCursor);
+ StopDlg sdlg(m_Data->m_SvnContextListener,_parent,0,"Annotate",i18n("Annotate lines - hit cancel for abort"));
+ connect(this,SIGNAL(sigExtraLogMsg(const QString&)),&sdlg,SLOT(slotExtraMessage(const QString&)));
+ m_Data->m_Svnclient->annotate(blame,p,start,end,peg);
+ } catch (const svn::Exception&e) {
+ emit clientException(e.msg());
+ return;
+ }
+ if (blame.count()==0) {
+ ex = i18n("Got no annotate");
+ emit clientException(ex);
+ return;
+ }
+ EMIT_FINISHED;
+ BlameDisplay_impl::displayBlame(_acb?_acb:this,k,blame,_p,"blame_dlg");
+}
+
+bool SvnActions::makeGet(const svn::Revision&start, const QString&what, const QString&target,
+ const svn::Revision&peg,QWidget*_dlgparent)
+{
+ if (!m_Data->m_CurrentContext) return false;
+ CursorStack a(Qt::BusyCursor);
+ QWidget*dlgp=_dlgparent?_dlgparent:m_Data->m_ParentList->realWidget();
+ QString ex;
+ svn::Path p(what);
+ try {
+ StopDlg sdlg(m_Data->m_SvnContextListener,dlgp,
+ 0,"Content get",i18n("Getting content - hit cancel for abort"));
+ connect(this,SIGNAL(sigExtraLogMsg(const QString&)),&sdlg,SLOT(slotExtraMessage(const QString&)));
+ m_Data->m_Svnclient->get(p,target,start,peg);
+ } catch (const svn::Exception&e) {
+ emit clientException(e.msg());
+ return false;
+ } catch (...) {
+ ex = i18n("Error getting content");
+ emit clientException(ex);
+ return false;
+ }
+ return true;
+}
+
+void SvnActions::slotMakeCat(const svn::Revision&start, const QString&what, const QString&disp,const svn::Revision&peg,QWidget*_dlgparent)
+{
+ KTempFile content;
+ content.setAutoDelete(true);
+ if (!makeGet(start,what,content.name(),peg,_dlgparent)) {
+ return;
+ }
+ EMIT_FINISHED;
+ KMimeType::Ptr mptr;
+ mptr = KMimeType::findByFileContent(content.name());
+ KTrader::OfferList offers = KTrader::self()->query(mptr->name(), "Type == 'Application' or (exist Exec)");
+ if (offers.count()==0 || offers.first()->exec().isEmpty()) {
+ offers = KTrader::self()->query(mptr->name(), "Type == 'Application'");
+ }
+ KTrader::OfferList::ConstIterator it = offers.begin();
+ for( ; it != offers.end(); ++it ) {
+ if ((*it)->noDisplay())
+ continue;
+ break;
+ }
+
+ if (it!=offers.end()) {
+ content.setAutoDelete(false);
+ KRun::run(**it,KURL(content.name()),true);
+ return;
+ }
+ KTextBrowser*ptr;
+ QFile file(content.name());
+ file.open( IO_ReadOnly );
+ QByteArray co = file.readAll();
+
+ if (co.size()) {
+ KDialogBase*dlg = createDialog(&ptr,QString(i18n("Content of %1")).arg(disp),false,"cat_display_dlg");
+ if (dlg) {
+ ptr->setFont(KGlobalSettings::fixedFont());
+ ptr->setWordWrap(QTextEdit::NoWrap);
+ ptr->setText(QString::FROMUTF8(co,co.size()));
+ dlg->exec();
+ dlg->saveDialogSize(*(Kdesvnsettings::self()->config()),"cat_display_dlg",false);
+ delete dlg;
+ }
+ } else {
+ KMessageBox::information(_dlgparent?_dlgparent:m_Data->m_ParentList->realWidget(),
+ i18n("Got no content."));
+ }
+}
+
+bool SvnActions::makeMkdir(const QStringList&which,const QString&logMessage)
+{
+ if (!m_Data->m_CurrentContext||which.count()<1) return false;
+ svn::Targets targets(which);
+ try {
+ m_Data->m_Svnclient->mkdir(targets,logMessage);
+ }catch (const svn::Exception&e) {
+ emit clientException(e.msg());
+ return false;
+ }
+ return true;
+}
+
+QString SvnActions::makeMkdir(const QString&parentDir)
+{
+ if (!m_Data->m_CurrentContext) return QString::null;
+ QString ex;
+ bool isOk=false;
+ ex = KInputDialog::getText(i18n("New folder"),i18n("Enter folder name:"),QString::null,&isOk);
+ if (!isOk) {
+ return QString::null;
+ }
+ svn::Path target(parentDir);
+ target.addComponent(ex);
+ ex = "";
+
+ QString logMessage=QString::null;
+ try {
+ m_Data->m_Svnclient->mkdir(target,logMessage);
+ }catch (const svn::Exception&e) {
+ emit clientException(e.msg());
+ return QString::null;
+ }
+
+ ex = target.path();
+ return ex;
+}
+
+QString SvnActions::getInfo(QPtrList<SvnItem> lst,const svn::Revision&rev,const svn::Revision&peg,bool recursive,bool all)
+{
+ QStringList l;
+ QString res = "";
+ SvnItem*item;
+ for (item=lst.first();item;item=lst.next()) {
+ if (all) res+="<h4 align=\"center\">"+item->fullName()+"</h4>";
+ res += getInfo(item->fullName(),rev,peg,recursive,all);
+ }
+ return res;
+}
+
+QString SvnActions::getInfo(const QString& _what,const svn::Revision&rev,const svn::Revision&peg,bool recursive,bool all)
+{
+ if (!m_Data->m_CurrentContext) return QString::null;
+ QString ex;
+ svn::InfoEntries entries;
+ if (recursive) {
+ try {
+ StopDlg sdlg(m_Data->m_SvnContextListener,m_Data->m_ParentList->realWidget(),0,"Details",
+ i18n("Retrieving infos - hit cancel for abort"));
+ connect(this,SIGNAL(sigExtraLogMsg(const QString&)),&sdlg,SLOT(slotExtraMessage(const QString&)));
+ svn::InfoEntries e;
+ entries = (m_Data->m_Svnclient->info(_what+
+ (_what.find("@")>-1&&!svn::Url::isValid(_what)?"@BASE":""),recursive?svn::DepthInfinity:svn::DepthEmpty,rev,peg));
+ } catch (const svn::Exception&e) {
+ emit clientException(e.msg());
+ return QString::null;
+ }
+ } else {
+ svn::InfoEntry info;
+ if (!singleInfo(_what,rev,info,peg)) {
+ return QString::null;
+ }
+ entries.append(info);
+ }
+ //if (!all) EMIT_FINISHED;
+ QString text = "";
+ svn::InfoEntries::const_iterator it;
+ static QString rb = "<tr><td><nobr><font color=\"black\">";
+ static QString re = "</font></nobr></td></tr>\n";
+ static QString cs = "</font></nobr>:</td><td><nobr><font color=\"black\">";
+ unsigned int val = 0;
+ for (it=entries.begin();it!=entries.end();++it) {
+ if (val>0) {
+ text+="<hline>";
+ }
+ text+="<p align=\"center\">";
+ text+="<table cellspacing=0 cellpadding=0>";
+ if ((*it).Name().length()) {
+ text+=rb+i18n("Name")+cs+((*it).Name())+re;
+ }
+ if (all) {
+ text+=rb+i18n("URL")+cs+((*it).url())+re;
+ if ((*it).reposRoot().length()) {
+ text+=rb+i18n("Canonical repository url")+cs+((*it).reposRoot())+re;
+ }
+ if ((*it).checksum().length()) {
+ text+=rb+i18n("Checksum")+cs+((*it).checksum())+re;
+ }
+ }
+ text+=rb+i18n("Type")+cs;
+ switch ((*it).kind()) {
+ case svn_node_none:
+ text+=i18n("Absent");
+ break;
+ case svn_node_file:
+ text+=i18n("File");
+ break;
+ case svn_node_dir:
+ text+=i18n("Folder");
+ break;
+ case svn_node_unknown:
+ default:
+ text+=i18n("Unknown");
+ break;
+ }
+ text+=re;
+ if (all) {
+ text+=rb+i18n("Schedule")+cs;
+ switch ((*it).Schedule()) {
+ case svn_wc_schedule_normal:
+ text+=i18n("Normal");
+ break;
+ case svn_wc_schedule_add:
+ text+=i18n("Addition");
+ break;
+ case svn_wc_schedule_delete:
+ text+=i18n("Deletion");
+ break;
+ case svn_wc_schedule_replace:
+ text+=i18n("Replace");
+ break;
+ default:
+ text+=i18n("Unknown");
+ break;
+ }
+ text+=re;
+ text+=rb+i18n("UUID")+cs+((*it).uuid())+re;
+ }
+ text+=rb+i18n("Last author")+cs+((*it).cmtAuthor())+re;
+ if ((*it).cmtDate()>0) {
+ text+=rb+i18n("Last committed")+cs+helpers::sub2qt::DateTime2qtString((*it).cmtDate())+re;
+ }
+ text+=rb+i18n("Last revision")+cs+(*it).cmtRev().toString()+re;
+ if ((*it).textTime()>0) {
+ text+=rb+i18n("Content last changed")+cs+helpers::sub2qt::DateTime2qtString((*it).textTime())+re;
+ }
+ if (all) {
+ if ((*it).propTime()>0) {
+ text+=rb+i18n("Property last changed")+cs+helpers::sub2qt::DateTime2qtString((*it).propTime())+re;
+ }
+ if ((*it).conflictNew().length()) {
+ text+=rb+i18n("New version of conflicted file")+cs+((*it).conflictNew())+re;
+ }
+ if ((*it).conflictOld().length()) {
+ text+=rb+i18n("Old version of conflicted file")+cs+((*it).conflictOld())+re;
+ }
+ if ((*it).conflictWrk().length()) {
+ text+=rb+i18n("Working version of conflicted file")+
+ cs+((*it).conflictWrk())+re;
+ }
+ if ((*it).prejfile().length()) {
+ text+=rb+i18n("Property reject file")+
+ cs+((*it).prejfile())+re;
+ }
+
+ if ((*it).copyfromUrl().length()) {
+ text+=rb+i18n("Copy from URL")+cs+((*it).copyfromUrl())+re;
+ }
+ if ((*it).lockEntry().Locked()) {
+ text+=rb+i18n("Lock token")+cs+((*it).lockEntry().Token())+re;
+ text+=rb+i18n("Owner")+cs+((*it).lockEntry().Owner())+re;
+ text+=rb+i18n("Locked on")+cs+
+ helpers::sub2qt::DateTime2qtString((*it).lockEntry().Date())+
+ re;
+ text+=rb+i18n("Lock comment")+cs+
+ (*it).lockEntry().Comment()+re;
+ } else {
+ svn::SharedPointer<svn::Status> d;
+ if (checkReposLockCache(_what,d)&& d && d->lockEntry().Locked()) {
+ text+=rb+i18n("Lock token")+cs+(d->lockEntry().Token())+re;
+ text+=rb+i18n("Owner")+cs+(d->lockEntry().Owner())+re;
+ text+=rb+i18n("Locked on")+cs+
+ helpers::sub2qt::DateTime2qtString(d->lockEntry().Date())+
+ re;
+ text+=rb+i18n("Lock comment")+cs+
+ d->lockEntry().Comment()+re;
+ }
+ }
+ }
+ text+="</table></p>\n";
+ }
+ return text;
+}
+
+void SvnActions::makeInfo(QPtrList<SvnItem> lst,const svn::Revision&rev,const svn::Revision&peg,bool recursive)
+{
+ QStringList l;
+ QString res = "<html><head></head><body>";
+ SvnItem*item;
+ for (item=lst.first();item;item=lst.next()) {
+ QString text = getInfo(item->fullName(),rev,peg,recursive,true);
+ if (!text.isEmpty()) {
+ res+="<h4 align=\"center\">"+item->fullName()+"</h4>";
+ res+=text;
+ }
+ }
+ res+="</body></html>";
+ KTextBrowser*ptr;
+ KDialogBase*dlg = createDialog(&ptr,QString(i18n("Infolist")),false,"info_dialog");
+ if (dlg) {
+ ptr->setText(res);
+ dlg->exec();
+ dlg->saveDialogSize(*(Kdesvnsettings::self()->config()),"info_dialog",false);
+ delete dlg;
+ }
+}
+
+void SvnActions::makeInfo(const QStringList&lst,const svn::Revision&rev,const svn::Revision&peg,bool recursive)
+{
+ QString text = "";
+ for (unsigned int i=0; i < lst.count();++i) {
+ QString res = getInfo(lst[i],rev,peg,recursive,true);
+ if (!res.isEmpty()) {
+ text+="<h4 align=\"center\">"+lst[i]+"</h4>";
+ text+=res;
+ }
+ }
+ text = "<html><head></head><body>"+text+"</body></html>";
+ KTextBrowser*ptr;
+ KDialogBase*dlg = createDialog(&ptr,QString(i18n("Infolist")),false,"info_dialog");
+ if (dlg) {
+ ptr->setText(text);
+ dlg->exec();
+ dlg->saveDialogSize(*(Kdesvnsettings::self()->config()),"info_dialog",false);
+ delete dlg;
+ }
+}
+
+
+/*!
+ \fn SvnActions::slotProperties()
+ */
+void SvnActions::slotProperties()
+{
+ /// @todo remove reference to parentlist
+ if (!m_Data->m_CurrentContext) return;
+ if (!m_Data->m_ParentList) return;
+ SvnItem*k = m_Data->m_ParentList->Selected();
+ if (!k) return;
+ PropertiesDlg dlg(k,svnclient(),
+ m_Data->m_ParentList->isWorkingCopy()?svn::Revision::WORKING:svn::Revision::HEAD);
+ connect(&dlg,SIGNAL(clientException(const QString&)),m_Data->m_ParentList->realWidget(),SLOT(slotClientException(const QString&)));
+ dlg.resize(dlg.configDialogSize(*(Kdesvnsettings::self()->config()), "properties_dlg"));
+ if (dlg.exec()!=QDialog::Accepted) {
+ return;
+ }
+ dlg.saveDialogSize(*(Kdesvnsettings::self()->config()),"properties_dlg",false);
+ QString ex;
+ svn::PropertiesMap setList;
+ QValueList<QString> delList;
+ dlg.changedItems(setList,delList);
+ changeProperties(setList,delList,k->fullName());
+ k->refreshStatus();
+ EMIT_FINISHED;
+}
+
+bool SvnActions::changeProperties(const svn::PropertiesMap&setList,const QValueList<QString>&delList,const QString&path)
+{
+ try {
+ StopDlg sdlg(m_Data->m_SvnContextListener,m_Data->m_ParentList->realWidget(),0,"Applying properties","<center>Applying<br>hit cancel for abort</center>");
+ connect(this,SIGNAL(sigExtraLogMsg(const QString&)),&sdlg,SLOT(slotExtraMessage(const QString&)));
+ unsigned int pos;
+ for (pos = 0; pos<delList.size();++pos) {
+ m_Data->m_Svnclient->propdel(delList[pos],svn::Path(path));
+ }
+ svn::PropertiesMap::ConstIterator it;
+ for (it=setList.begin(); it!=setList.end();++it) {
+ m_Data->m_Svnclient->propset(it.key(),it.data(),svn::Path(path));
+ }
+ } catch (const svn::Exception&e) {
+ emit clientException(e.msg());
+ return false;
+ }
+ return true;
+}
+
+/*!
+ \fn SvnActions::slotCommit()
+ */
+void SvnActions::slotCommit()
+{
+ if (!m_Data->m_CurrentContext||!m_Data->m_ParentList->isWorkingCopy()) {
+ return;
+ }
+ QPtrList<SvnItem> which;
+ m_Data->m_ParentList->SelectionList(&which);
+ SvnItem*cur;
+ QPtrListIterator<SvnItem> liter(which);
+
+ svn::Pathes targets;
+ if (which.count()==0) {
+ targets.push_back(svn::Path("."));
+ } else {
+ while ( (cur=liter.current())!=0) {
+ ++liter;
+ targets.push_back(svn::Path(
+ m_Data->m_ParentList->relativePath(cur)
+ ));
+ }
+ }
+ if (m_Data->m_ParentList->baseUri().length()>0) {
+ chdir(m_Data->m_ParentList->baseUri().local8Bit());
+ }
+ if (makeCommit(targets) && Kdesvnsettings::log_cache_on_open()) {
+ startFillCache(m_Data->m_ParentList->baseUri());
+ }
+}
+
+bool SvnActions::makeCommit(const svn::Targets&targets)
+{
+ bool ok,keeplocks;
+ svn::Depth depth;
+ svn::Revision nnum;
+ svn::Targets _targets;
+ svn::Pathes _deldir;
+ bool review = Kdesvnsettings::review_commit();
+ QString msg,_p;
+
+ if (!doNetworking()) {
+ emit clientException(i18n("Not commiting because networking is disabled"));
+ return false;
+ }
+
+ stopFillCache();
+ if (!review) {
+ msg = Logmsg_impl::getLogmessage(&ok,&depth,&keeplocks,
+ m_Data->m_ParentList->realWidget(),"logmsg_impl");
+ if (!ok) {
+ return false;
+ }
+ _targets = targets;
+ } else {
+ Logmsg_impl::logActionEntries _check,_uncheck,_result;
+ svn::StatusEntries _Cache;
+ depth=svn::DepthEmpty;
+ /// @todo filter out double entries
+ for (unsigned j = 0; j < targets.size(); ++j) {
+ svn::Revision where = svn::Revision::HEAD;
+ try {
+ StopDlg sdlg(m_Data->m_SvnContextListener,m_Data->m_ParentList->realWidget(),0,i18n("Status / List"),i18n("Creating list / check status"));
+ _Cache = m_Data->m_Svnclient->status(targets.target(j).path(),svn::DepthInfinity,false,false,false,where);
+ } catch (const svn::Exception&e) {
+ emit clientException(e.msg());
+ return false;
+ }
+ for (unsigned int i = 0; i < _Cache.count();++i) {
+ _p = _Cache[i]->path();
+ if (_Cache[i]->isRealVersioned()&& (
+ _Cache[i]->textStatus()==svn_wc_status_modified||
+ _Cache[i]->textStatus()==svn_wc_status_added||
+ _Cache[i]->textStatus()==svn_wc_status_replaced||
+ _Cache[i]->textStatus()==svn_wc_status_deleted||
+ _Cache[i]->propStatus()==svn_wc_status_modified
+ ) ) {
+ if (_Cache[i]->textStatus()==svn_wc_status_deleted) {
+ _check.append(Logmsg_impl::logActionEntry(_p,i18n("Delete"),Logmsg_impl::logActionEntry::DELETE));
+ } else {
+ _check.append(Logmsg_impl::logActionEntry(_p,i18n("Commit"),Logmsg_impl::logActionEntry::COMMIT));
+ }
+ } else if (_Cache[i]->textStatus()==svn_wc_status_missing) {
+ _uncheck.append(Logmsg_impl::logActionEntry(_p,i18n("Delete and Commit"),Logmsg_impl::logActionEntry::MISSING_DELETE));
+ } else if (!_Cache[i]->isVersioned()) {
+ _uncheck.append(Logmsg_impl::logActionEntry(_p,i18n("Add and Commit"),Logmsg_impl::logActionEntry::ADD_COMMIT));
+ }
+ }
+ }
+ msg = Logmsg_impl::getLogmessage(_check,_uncheck,this,_result,&ok,&keeplocks,
+ m_Data->m_ParentList->realWidget(),"logmsg_impl");
+ if (!ok||_result.count()==0) {
+ return false;
+ }
+ svn::Pathes _add,_commit,_delete;
+ for (unsigned int i=0; i < _result.count();++i) {
+ if (_result[i]._kind==Logmsg_impl::logActionEntry::DELETE) {
+ QFileInfo fi(_result[i]._name);
+ if (fi.isDir()) {
+ depth = svn::DepthInfinity;
+ }
+ }
+ _commit.append(_result[i]._name);
+ if (_result[i]._kind==Logmsg_impl::logActionEntry::ADD_COMMIT) {
+ _add.append(_result[i]._name);
+ } else if (_result[i]._kind==Logmsg_impl::logActionEntry::MISSING_DELETE) {
+ _delete.append(_result[i]._name);
+ }
+ }
+ if (_add.count()>0) {
+ if (!addItems(_add,svn::DepthEmpty)) {
+ return false;
+ }
+ }
+ if (_delete.count()>0) {
+ makeDelete(_delete);
+ }
+ _targets = svn::Targets(_commit);
+ }
+
+ try {
+ StopDlg sdlg(m_Data->m_SvnContextListener,m_Data->m_ParentList->realWidget(),0,i18n("Commiting"),
+ i18n("Commiting - hit cancel for abort"));
+ connect(this,SIGNAL(sigExtraLogMsg(const QString&)),&sdlg,SLOT(slotExtraMessage(const QString&)));
+ nnum = m_Data->m_Svnclient->commit(_targets,msg,depth,keeplocks);
+ } catch (const svn::Exception&e) {
+ emit clientException(e.msg());
+ return false;
+ }
+ EMIT_REFRESH;
+ emit sendNotify(i18n("Committed revision %1.").arg(nnum.toString()));
+ return true;
+}
+
+/*!
+ \fn SvnActions::wroteStdin(KProcess*)
+ */
+void SvnActions::wroteStdin(KProcess*proc)
+{
+ if (!proc) return;
+ kdDebug()<<"void SvnActions::wroteStdin(KProcess*proc)"<<endl;
+ proc->closeStdin();
+}
+
+void SvnActions::receivedStderr(KProcess*proc,char*buff,int len)
+{
+ if (!proc || !buff || len == 0) {
+ return;
+ }
+ QString msg(QCString(buff,len));
+ emit sendNotify(msg);
+}
+
+void SvnActions::procClosed(KProcess*proc)
+{
+ if (!proc) return;
+ QMap<KProcess*,QStringList>::iterator it;
+ if ( (it=m_Data->m_tempfilelist.find(proc))!=m_Data->m_tempfilelist.end()) {
+ for (QStringList::iterator it2 = (*it).begin();
+ it2 != (*it).end();++it2) {
+ ::unlink((*it2).ascii());
+ }
+ m_Data->m_tempfilelist.erase(it);
+ }
+ if ( (it=m_Data->m_tempdirlist.find(proc))!=m_Data->m_tempdirlist.end()) {
+ for (QStringList::iterator it2 = (*it).begin();
+ it2 != (*it).end();++it2) {
+ KIO::NetAccess::del((*it2),0);
+ }
+ m_Data->m_tempdirlist.erase(it);
+ }
+ delete proc;
+}
+
+bool SvnActions::get(const QString&what,const QString& to,const svn::Revision&rev,const svn::Revision&peg,QWidget*p)
+{
+ svn::Revision _peg = peg;
+ if (_peg == svn::Revision::UNDEFINED) {
+ _peg = rev;
+ }
+
+ try {
+ StopDlg sdlg(m_Data->m_SvnContextListener,p?p:m_Data->m_ParentList->realWidget(),0,"Downloading",
+ i18n("Download - hit cancel for abort"));
+ connect(this,SIGNAL(sigExtraLogMsg(const QString&)),&sdlg,SLOT(slotExtraMessage(const QString&)));
+ m_Data->m_Svnclient->get(svn::Path(what),
+ to,rev,_peg);
+ } catch (const svn::Exception&e) {
+ emit clientException(e.msg());
+ return false;
+ }
+ return true;
+}
+
+/*!
+ \fn SvnActions::makeDiff(const QString&,const svn::Revision&start,const svn::Revision&end)
+ */
+void SvnActions::makeDiff(const QString&what,const svn::Revision&start,const svn::Revision&end,const svn::Revision&_peg,bool isDir)
+{
+ makeDiff(what,start,what,end,_peg,isDir,m_Data->m_ParentList->realWidget());
+}
+
+void SvnActions::makeDiff(const QString&p1,const svn::Revision&start,const QString&p2,const svn::Revision&end)
+{
+ makeDiff(p1,start,p2,end,(QWidget*)0);
+}
+
+void SvnActions::makeDiff(const QString&p1,const svn::Revision&start,const QString&p2,const svn::Revision&end,QWidget*p)
+{
+ if (!doNetworking()&&start!=svn::Revision::BASE && end!=svn::Revision::WORKING) {
+ emit sendNotify(i18n("Can not do this diff because networking is disabled."));
+ kdDebug()<<"No diff 'cause no network"<<endl;
+ return;
+ }
+ if (m_Data->isExternalDiff()) {
+ kdDebug()<<"External diff..."<<endl;
+ svn::InfoEntry info;
+ if (singleInfo(p1,start,info)) {
+ makeDiff(p1,start,p2,end,end,info.isDir(),p);
+ }
+ return;
+ }
+ makeDiffinternal(p1,start,p2,end,p);
+}
+
+void SvnActions::makeDiffExternal(const QString&p1,const svn::Revision&start,const QString&p2,const svn::Revision&end,const svn::Revision&_peg,
+ bool isDir,QWidget*p,bool rec)
+{
+ QString edisp = Kdesvnsettings::external_diff_display();
+ QStringList wlist = QStringList::split(" ",edisp);
+ QFileInfo f1(p1);
+ QFileInfo f2(p2);
+ KTempFile tfile(QString::null,f1.fileName()+"-"+start.toString()),tfile2(QString::null,f2.fileName()+"-"+end.toString());
+ QString s1 = f1.fileName()+"-"+start.toString();
+ QString s2 = f2.fileName()+"-"+end.toString();
+ KTempDir tdir1;
+ tdir1.setAutoDelete(true);
+ tfile.setAutoDelete(true);
+ tfile2.setAutoDelete(true);
+ QString first,second;
+ svn::Revision peg = _peg;
+
+ if (start != svn::Revision::WORKING) {
+ first = isDir?tdir1.name()+"/"+s1:tfile.name();
+ } else {
+ first = p1;
+ }
+ if (end!=svn::Revision::WORKING) {
+ second = isDir?tdir1.name()+"/"+s2:tfile2.name();
+ } else {
+ second = p2;
+ }
+ if (second == first) {
+ KMessageBox::error(m_Data->m_ParentList->realWidget(),i18n("Both entries seems to be the same, can not diff."));
+ return;
+ }
+ kdDebug()<<"Diff: "<<peg.toString()<<endl;
+
+ if (start != svn::Revision::WORKING) {
+ if (!isDir) {
+ if (!get(p1,tfile.name(),start,peg,p)) {
+ return;
+ }
+ } else {
+ if (!makeCheckout(p1,first,start,peg,
+ rec?svn::DepthInfinity:svn::DepthFiles,true,false,false,false,p)) {
+ return;
+ }
+ }
+ }
+ if (end!=svn::Revision::WORKING) {
+ if (!isDir) {
+ if (!get(p2,tfile2.name(),end,peg,p)) {
+ return;
+ }
+ } else {
+ if (!makeCheckout(p2,second,end,peg,
+ rec?svn::DepthInfinity:svn::DepthFiles,true,false,false,false,p)) {
+ return;
+ }
+ }
+ }
+ KProcess*proc = new KProcess();
+ for ( QStringList::Iterator it = wlist.begin();it!=wlist.end();++it) {
+ if (*it=="%1") {
+ *proc<<first;
+ } else if (*it=="%2") {
+ *proc<<second;
+ } else {
+ *proc << *it;
+ }
+ }
+ connect(proc,SIGNAL(processExited(KProcess*)),this,SLOT(procClosed(KProcess*)));
+ connect(proc,SIGNAL(receivedStderr(KProcess*,char*,int)),this,SLOT(receivedStderr(KProcess*,char*,int)));
+ connect(proc,SIGNAL(receivedStdout(KProcess*,char*,int)),this,SLOT(receivedStderr(KProcess*,char*,int)));
+ if (proc->start(m_Data->runblocked?KProcess::Block:KProcess::NotifyOnExit,KProcess::All)) {
+ if (!m_Data->runblocked) {
+ if (!isDir) {
+ tfile2.setAutoDelete(false);
+ tfile.setAutoDelete(false);
+ m_Data->m_tempfilelist[proc].append(tfile.name());
+ m_Data->m_tempfilelist[proc].append(tfile2.name());
+ } else {
+ tdir1.setAutoDelete(false);
+ m_Data->m_tempdirlist[proc].append(tdir1.name());
+ }
+ }
+ return;
+ } else {
+ emit sendNotify(i18n("Diff-process could not started, check command."));
+ }
+ delete proc;
+ return;
+}
+
+void SvnActions::makeDiff(const QString&p1,const svn::Revision&start,const QString&p2,const svn::Revision&end,const svn::Revision&_peg,bool isDir,QWidget*p)
+{
+ if (m_Data->isExternalDiff()) {
+ kdDebug()<<"External diff 2..."<<endl;
+ makeDiffExternal(p1,start,p2,end,_peg,isDir,p);
+ } else {
+ makeDiffinternal(p1,start,p2,end,p,_peg);
+ }
+}
+
+void SvnActions::makeDiffinternal(const QString&p1,const svn::Revision&r1,const QString&p2,const svn::Revision&r2,QWidget*p,const svn::Revision&_peg)
+{
+ if (!m_Data->m_CurrentContext) return;
+ QByteArray ex;
+ KTempDir tdir;
+ tdir.setAutoDelete(true);
+ QString tn = QString("%1/%2").arg(tdir.name()).arg("/svndiff");
+ bool ignore_content = Kdesvnsettings::diff_ignore_content();
+ QWidget*parent = p?p:m_Data->m_ParentList->realWidget();
+ QStringList extraOptions;
+ if (Kdesvnsettings::diff_ignore_spaces())
+ {
+ extraOptions.append("-b");
+ }
+ if (Kdesvnsettings::diff_ignore_all_white_spaces())
+ {
+ extraOptions.append("-w");
+ }
+ svn::Revision peg = _peg==svn::Revision::UNDEFINED?r2:_peg;
+
+ try {
+ StopDlg sdlg(m_Data->m_SvnContextListener,parent,0,"Diffing",
+ i18n("Diffing - hit cancel for abort"));
+ connect(this,SIGNAL(sigExtraLogMsg(const QString&)),&sdlg,SLOT(slotExtraMessage(const QString&)));
+ if (p1==p2 && (r1.isRemote()||r2.isRemote())) {
+ kdDebug()<<"Pegged diff"<<endl;
+ ex = m_Data->m_Svnclient->diff_peg(svn::Path(tn),
+ svn::Path(p1),svn::Path(),r1, r2,peg,
+ svn::DepthInfinity,false,false,ignore_content,extraOptions,svn::StringArray());
+ } else {
+ ex = m_Data->m_Svnclient->diff(svn::Path(tn),
+ svn::Path(p1),svn::Path(p2),svn::Path(),
+ r1, r2,
+ svn::DepthInfinity,false,false,ignore_content,extraOptions,svn::StringArray());
+ }
+ } catch (const svn::Exception&e) {
+ emit clientException(e.msg());
+ return;
+ }
+ EMIT_FINISHED;
+ if (ex.isEmpty()) {
+ emit clientException(i18n("No difference to display"));
+ return;
+ }
+ dispDiff(ex);
+}
+
+void SvnActions::makeNorecDiff(const QString&p1,const svn::Revision&r1,const QString&p2,const svn::Revision&r2,QWidget*_p)
+{
+ if (!m_Data->m_CurrentContext) return;
+ if (m_Data->isExternalDiff()) {
+ svn::InfoEntry info;
+ if (singleInfo(p1,r1,info)) {
+ makeDiffExternal(p1,r1,p2,r2,r2,info.isDir(),_p,false);
+ }
+ return;
+ }
+ QStringList extraOptions;
+ if (Kdesvnsettings::diff_ignore_spaces())
+ {
+ extraOptions.append("-b");
+ }
+ if (Kdesvnsettings::diff_ignore_all_white_spaces())
+ {
+ extraOptions.append("-w");
+ }
+ QByteArray ex;
+ KTempDir tdir;
+ tdir.setAutoDelete(true);
+ kdDebug()<<"Non recourse diff"<<endl;
+ QString tn = QString("%1/%2").arg(tdir.name()).arg("/svndiff");
+ bool ignore_content = Kdesvnsettings::diff_ignore_content();
+ try {
+ StopDlg sdlg(m_Data->m_SvnContextListener,_p?_p:m_Data->m_ParentList->realWidget(),0,"Diffing","Diffing - hit cancel for abort");
+ connect(this,SIGNAL(sigExtraLogMsg(const QString&)),&sdlg,SLOT(slotExtraMessage(const QString&)));
+ ex = m_Data->m_Svnclient->diff(svn::Path(tn),
+ svn::Path(p1),svn::Path(p2),svn::Path(),
+ r1, r2,
+ svn::DepthEmpty,false,false,ignore_content,extraOptions,svn::StringArray());
+ } catch (const svn::Exception&e) {
+ emit clientException(e.msg());
+ return;
+ }
+ EMIT_FINISHED;
+ if (ex.isEmpty()) {
+ emit clientException(i18n("No difference to display"));
+ return;
+ }
+
+ dispDiff(ex);
+}
+
+void SvnActions::dispDiff(const QByteArray&ex)
+{
+ QString what = Kdesvnsettings::external_diff_display();
+ int r = KProcess::Stdin|KProcess::Stderr;
+
+ if (Kdesvnsettings::use_external_diff() && (what.find("%1")==-1 || what.find("%2")==-1)) {
+ QStringList wlist = QStringList::split(" ",what);
+ KProcess*proc = new KProcess();
+ bool fname_used = false;
+ KTempFile tfile;
+ tfile.setAutoDelete(false);
+
+ for ( QStringList::Iterator it = wlist.begin();it!=wlist.end();++it) {
+ if (*it=="%f") {
+ fname_used = true;
+ QDataStream*ds = tfile.dataStream();
+ ds->writeRawBytes(ex,ex.size());
+ tfile.close();
+ *proc<<tfile.name();
+ } else {
+ *proc << *it;
+ }
+ }
+
+ connect(proc,SIGNAL(processExited(KProcess*)),this,SLOT(procClosed(KProcess*)));
+ connect(proc,SIGNAL(receivedStderr(KProcess*,char*,int)),this,SLOT(receivedStderr(KProcess*,char*,int)));
+ if (!fname_used) {
+ connect(proc,SIGNAL(wroteStdin(KProcess*)),this,SLOT(wroteStdin(KProcess*)));
+ }
+ if (proc->start(KProcess::NotifyOnExit,fname_used?KProcess::Stderr:(KProcess::Communication)r)) {
+ if (!fname_used) proc->writeStdin(ex,ex.size());
+ else m_Data->m_tempfilelist[proc].append(tfile.name());
+ return;
+ } else {
+ emit sendNotify(i18n("Display-process could not started, check command."));
+ }
+ delete proc;
+ }
+ bool need_modal = m_Data->runblocked||KApplication::activeModalWidget()!=0;
+ if (need_modal||!m_Data->m_DiffBrowserPtr||!m_Data->m_DiffDialog) {
+ DiffBrowser*ptr;
+
+ if (!need_modal && m_Data->m_DiffBrowserPtr) {
+ delete m_Data->m_DiffBrowserPtr;
+ }
+ KDialogBase*dlg = createDialog(&ptr,QString(i18n("Diff display")),false,
+ "diff_display",false,need_modal,
+ KStdGuiItem::saveAs());
+ if (dlg) {
+ QWidget*wd = dlg->mainWidget();
+ if (wd) {
+ EncodingSelector_impl * ls = new EncodingSelector_impl("",wd);
+ QObject::connect(ls,SIGNAL(TextCodecChanged(const QString&)),
+ ptr,SLOT(slotTextCodecChanged(const QString&)));
+ }
+ QObject::connect(dlg,SIGNAL(user1Clicked()),ptr,SLOT(saveDiff()));
+ ptr->setText(ex);
+ if (need_modal) {
+ ptr->setFocus();
+ dlg->exec();
+ dlg->saveDialogSize(*(Kdesvnsettings::self()->config()),"diff_display",false);
+ delete dlg;
+ return;
+ } else {
+ m_Data->m_DiffBrowserPtr=ptr;
+ m_Data->m_DiffDialog=dlg;
+ }
+ }
+ } else {
+ m_Data->m_DiffBrowserPtr->setText(ex);
+ m_Data->m_DiffBrowserPtr->setFocus();
+ }
+ if (m_Data->m_DiffDialog) {
+ m_Data->m_DiffDialog->show();
+ m_Data->m_DiffDialog->raise();
+ }
+}
+
+
+/*!
+ \fn SvnActions::makeUpdate(const QString&what,const svn::Revision&rev,bool recurse)
+ */
+void SvnActions::makeUpdate(const QStringList&what,const svn::Revision&rev,bool recurse)
+{
+ if (!m_Data->m_CurrentContext) return;
+ QString ex;
+ svn::Revisions ret;
+ stopCheckUpdateThread();
+ try {
+ StopDlg sdlg(m_Data->m_SvnContextListener,m_Data->m_ParentList->realWidget(),0,"Making update",
+ i18n("Making update - hit cancel for abort"));
+ connect(this,SIGNAL(sigExtraLogMsg(const QString&)),&sdlg,SLOT(slotExtraMessage(const QString&)));
+ svn::Targets pathes(what);
+ ret = m_Data->m_Svnclient->update(pathes,rev, recurse?svn::DepthInfinity:svn::DepthFiles,false,false,true);
+ } catch (const svn::Exception&e) {
+ emit clientException(e.msg());
+ return;
+ }
+ removeFromUpdateCache(what,!recurse);
+ EMIT_REFRESH;
+ EMIT_FINISHED;
+}
+
+/*!
+ \fn SvnActions::slotUpdateHeadRec()
+ */
+void SvnActions::slotUpdateHeadRec()
+{
+ prepareUpdate(false);
+}
+
+
+/*!
+ \fn SvnActions::prepareUpdate(bool ask)
+ */
+void SvnActions::prepareUpdate(bool ask)
+{
+ if (!m_Data->m_ParentList||!m_Data->m_ParentList->isWorkingCopy()) return;
+ SvnItemList k;
+ m_Data->m_ParentList->SelectionList(&k);
+
+ QStringList what;
+ if (k.count()==0) {
+ what.append(m_Data->m_ParentList->baseUri());
+ } else {
+ SvnItemListIterator liter(k);
+ SvnItem*cur;
+ while ((cur=liter.current())!=0){
+ ++liter;
+ what.append(cur->fullName());
+ }
+ }
+ svn::Revision r(svn::Revision::HEAD);
+ if (ask) {
+ Rangeinput_impl*rdlg;
+ KDialog*dlg = createDialog(&rdlg,QString(i18n("Revisions")),true);
+ if (!dlg) {
+ return;
+ }
+ rdlg->setStartOnly(true);
+ /* just here cause layout has changed meanwhile */
+ dlg->resize( QSize(120,60).expandedTo(dlg->minimumSizeHint()) );
+ int result;
+ if ((result=dlg->exec())==QDialog::Accepted) {
+ Rangeinput_impl::revision_range range = rdlg->getRange();
+ r=range.first;
+ }
+ delete dlg;
+ if (result!=QDialog::Accepted) return;
+ }
+ makeUpdate(what,r,true);
+}
+
+
+/*!
+ \fn SvnActions::slotUpdateTo()
+ */
+void SvnActions::slotUpdateTo()
+{
+ prepareUpdate(true);
+}
+
+
+/*!
+ \fn SvnActions::slotAdd()
+ */
+void SvnActions::slotAdd()
+{
+ makeAdd(false);
+}
+
+void SvnActions::slotAddRec()
+{
+ makeAdd(true);
+}
+
+void SvnActions::makeAdd(bool rec)
+{
+ if (!m_Data->m_CurrentContext) return;
+ if (!m_Data->m_ParentList) return;
+ QPtrList<SvnItem> lst;
+ m_Data->m_ParentList->SelectionList(&lst);
+ if (lst.count()==0) {
+ KMessageBox::error(m_Data->m_ParentList->realWidget(),i18n("Which files or directories should I add?"));
+ return;
+ }
+ QValueList<svn::Path> items;
+ SvnItemListIterator liter(lst);
+ SvnItem*cur;
+ while ((cur=liter.current())!=0){
+ ++liter;
+ if (cur->isVersioned()) {
+ KMessageBox::error(m_Data->m_ParentList->realWidget(),i18n("<center>The entry<br>%1<br>is versioned - break.</center>")
+ .arg(cur->fullName()));
+ return;
+ }
+ items.push_back(svn::Path(cur->fullName()));
+ }
+ addItems(items,rec?svn::DepthInfinity:svn::DepthEmpty);
+ liter.toFirst();
+#if 0
+ while ((cur=liter.current())!=0){
+ ++liter;
+ //cur->refreshStatus();
+
+ //emit sigRefreshCurrent(static_cast<FileListViewItem*>(cur->parent()));
+ }
+#else
+ emit sigRefreshCurrent(0);
+#endif
+}
+
+bool SvnActions::addItems(const QStringList&w,svn::Depth depth)
+{
+ QValueList<svn::Path> items;
+ for (unsigned int i = 0; i<w.count();++i) {
+ items.push_back(w[i]);
+ }
+ return addItems(items,depth);
+}
+
+bool SvnActions::addItems(const QValueList<svn::Path> &items,svn::Depth depth)
+{
+ QString ex;
+ try {
+ QValueList<svn::Path>::const_iterator piter;
+ for (piter=items.begin();piter!=items.end();++piter) {
+ m_Data->m_Svnclient->add((*piter),depth);
+ }
+ } catch (const svn::Exception&e) {
+ emit clientException(e.msg());
+ return false;
+ }
+ return true;
+}
+
+bool SvnActions::makeDelete(const QStringList&w)
+{
+ int answer = KMessageBox::questionYesNoList(0,i18n("Really delete these entries?"),w,i18n("Delete from repository"));
+ if (answer!=KMessageBox::Yes) {
+ return false;
+ }
+ svn::Pathes items;
+ for (unsigned int i = 0; i<w.count();++i) {
+ items.push_back(w[i]);
+ }
+ return makeDelete(items);
+}
+
+/*!
+ \fn SvnActions::makeDelete()
+ */
+bool SvnActions::makeDelete(const svn::Pathes&items)
+{
+ if (!m_Data->m_CurrentContext) return false;
+ QString ex;
+ try {
+ svn::Targets target(items);
+ m_Data->m_Svnclient->remove(target,false);
+ } catch (const svn::Exception&e) {
+ emit clientException(e.msg());
+ return false;
+ }
+ EMIT_FINISHED;
+ return true;
+}
+
+void SvnActions::slotCheckout()
+{
+ CheckoutExport(false);
+}
+
+void SvnActions::slotExport()
+{
+ CheckoutExport(true);
+}
+
+void SvnActions::slotCheckoutCurrent()
+{
+ CheckoutExportCurrent(false);
+}
+
+void SvnActions::slotExportCurrent()
+{
+ CheckoutExportCurrent(true);
+}
+
+void SvnActions::CheckoutExport(bool _exp)
+{
+ CheckoutInfo_impl*ptr;
+ KDialogBase * dlg = createDialog(&ptr,(_exp?i18n("Export repository"):i18n("Checkout a repository")),true,"checkout_export_dialog");
+ if (dlg) {
+ if (dlg->exec()==QDialog::Accepted) {
+ svn::Revision r = ptr->toRevision();
+ bool openit = ptr->openAfterJob();
+ bool ignoreExternal=ptr->ignoreExternals();
+ makeCheckout(ptr->reposURL(),ptr->targetDir(),r,r,
+ ptr->getDepth(),
+ _exp,
+ openit,
+ ignoreExternal,
+ ptr->overwrite(),0);
+ }
+ dlg->saveDialogSize(*(Kdesvnsettings::self()->config()),"checkout_export_dialog",false);
+ delete dlg;
+ }
+}
+
+void SvnActions::CheckoutExport(const QString&what,bool _exp,bool urlisTarget)
+{
+ CheckoutInfo_impl*ptr;
+ KDialog * dlg = createDialog(&ptr,_exp?i18n("Export a repository"):i18n("Checkout a repository"),true);
+ if (dlg) {
+ if (!urlisTarget) {
+ ptr->setStartUrl(what);
+ } else {
+ ptr->setTargetUrl(what);
+ }
+ if (dlg->exec()==QDialog::Accepted) {
+ svn::Revision r = ptr->toRevision();
+ bool openIt = ptr->openAfterJob();
+ bool ignoreExternal = ptr->ignoreExternals();
+ makeCheckout(ptr->reposURL(),ptr->targetDir(),r,r,ptr->getDepth(),_exp,openIt,ignoreExternal,ptr->overwrite(),0);
+ }
+ delete dlg;
+ }
+}
+
+void SvnActions::CheckoutExportCurrent(bool _exp)
+{
+ if ( !m_Data->m_ParentList || (!_exp&&m_Data->m_ParentList->isWorkingCopy()) ) return;
+ SvnItem*k = m_Data->m_ParentList->Selected();
+ if (k && !k->isDir()) {
+ KMessageBox::error(m_Data->m_ParentList->realWidget(),_exp?i18n("Exporting a file?"):i18n("Checking out a file?"));
+ return;
+ }
+ QString what;
+ if (!k) {
+ what = m_Data->m_ParentList->baseUri();
+ } else {
+ what = k->fullName();
+ }
+ CheckoutExport(what,_exp);
+}
+
+bool SvnActions::makeCheckout(const QString&rUrl,const QString&tPath,const svn::Revision&r,const svn::Revision&_peg,
+ svn::Depth depth,
+ // kind of operation
+ bool _exp,
+ // open after job
+ bool openIt,
+ // ignore externals
+ bool ignoreExternal,
+ // overwrite/force not versioned items
+ bool overwrite,
+ QWidget*_p
+ )
+{
+ QString fUrl = rUrl;
+ QString ex;
+ while (fUrl.endsWith("/")) {
+ fUrl.truncate(fUrl.length()-1);
+ }
+ svn::Path p(tPath);
+ svn::Revision peg = _peg;
+ if (r!=svn::Revision::BASE && r!=svn::Revision::WORKING && _peg==svn::Revision::UNDEFINED) {
+ peg = r;
+ }
+ if (!_exp||!m_Data->m_CurrentContext) reInitClient();
+ try {
+ StopDlg sdlg(m_Data->m_SvnContextListener,_p?_p:m_Data->m_ParentList->realWidget(),0,_exp?i18n("Export"):i18n("Checkout"),_exp?i18n("Exporting"):i18n("Checking out"));
+ connect(this,SIGNAL(sigExtraLogMsg(const QString&)),&sdlg,SLOT(slotExtraMessage(const QString&)));
+ if (_exp) {
+ /// @todo setup parameter for export operation
+ m_Data->m_Svnclient->doExport(svn::Path(fUrl),p,r,peg,overwrite,QString::null,ignoreExternal,depth);
+ } else {
+ m_Data->m_Svnclient->checkout(fUrl,p,r,peg,depth,ignoreExternal,overwrite);
+ }
+ } catch (const svn::Exception&e) {
+ emit clientException(e.msg());
+ return false;
+ }
+ if (openIt) {
+ if (!_exp) emit sigGotourl(tPath);
+ else kapp->invokeBrowser(tPath);
+ }
+ EMIT_FINISHED;
+
+ return true;
+}
+
+void SvnActions::slotRevert()
+{
+ if (!m_Data->m_ParentList||!m_Data->m_ParentList->isWorkingCopy()) return;
+ QPtrList<SvnItem> lst;
+ m_Data->m_ParentList->SelectionList(&lst);
+ QStringList displist;
+ SvnItemListIterator liter(lst);
+ SvnItem*cur;
+ if (lst.count()>0) {
+ while ((cur=liter.current())!=0){
+ if (!cur->isVersioned()) {
+ KMessageBox::error(m_Data->m_ParentList->realWidget(),i18n("<center>The entry<br>%1<br>is not versioned - break.</center>")
+ .arg(cur->fullName()));
+ return;
+ }
+ displist.append(cur->fullName());
+ ++liter;
+ }
+ } else {
+ displist.push_back(m_Data->m_ParentList->baseUri());
+ }
+ slotRevertItems(displist);
+ EMIT_REFRESH;
+}
+
+void SvnActions::slotRevertItems(const QStringList&displist)
+{
+ if (!m_Data->m_CurrentContext) return;
+ if (displist.count()==0) {
+ return;
+ }
+
+ svn::Depth depth;
+ RevertFormImpl*ptr;
+ KDialog * dlg = createDialog(&ptr,i18n("Revert entries"),true);
+ if (!dlg) {
+ return;
+ }
+ ptr->setDispList(displist);
+ if (dlg->exec()!=QDialog::Accepted) {
+ delete dlg;
+ return;
+ }
+ depth = ptr->getDepth();
+
+ QValueList<svn::Path> items;
+ for (unsigned j = 0; j<displist.count();++j) {
+ items.push_back(svn::Path((*(displist.at(j)))));
+ }
+ QString ex;
+
+ try {
+ StopDlg sdlg(m_Data->m_SvnContextListener,m_Data->m_ParentList->realWidget(),0,i18n("Revert"),i18n("Reverting items"));
+ connect(this,SIGNAL(sigExtraLogMsg(const QString&)),&sdlg,SLOT(slotExtraMessage(const QString&)));
+ svn::Targets target(items);
+ m_Data->m_Svnclient->revert(target,depth);
+ } catch (const svn::Exception&e) {
+ emit clientException(e.msg());
+ return;
+ }
+ // remove them from cache
+ for (unsigned int j = 0; j<items.count();++j) {
+ m_Data->m_Cache.deleteKey(items[j].path(),depth!=svn::DepthInfinity);
+// m_Data->m_Cache.dump_tree();
+ }
+ EMIT_FINISHED;
+}
+
+bool SvnActions::makeSwitch(const QString&rUrl,const QString&tPath,const svn::Revision&r,svn::Depth depth,const svn::Revision&peg,bool stickydepth,bool ignore_externals,bool allow_unversioned)
+{
+ if (!m_Data->m_CurrentContext) return false;
+ QString fUrl = rUrl;
+ QString ex;
+ while (fUrl.endsWith("/")) {
+ fUrl.truncate(fUrl.length()-1);
+ }
+ svn::Path p(tPath);
+ try {
+ StopDlg sdlg(m_Data->m_SvnContextListener,m_Data->m_ParentList->realWidget(),0,i18n("Switch url"),i18n("Switching url"));
+ connect(this,SIGNAL(sigExtraLogMsg(const QString&)),&sdlg,SLOT(slotExtraMessage(const QString&)));
+ m_Data->m_Svnclient->doSwitch(p,fUrl,r,depth,peg,stickydepth,ignore_externals,allow_unversioned);
+ } catch (const svn::Exception&e) {
+ emit clientException(e.msg());
+ return false;
+ }
+ EMIT_FINISHED;
+ return true;
+}
+
+bool SvnActions::makeRelocate(const QString&fUrl,const QString&tUrl,const QString&path,bool rec)
+{
+ if (!m_Data->m_CurrentContext) return false;
+ QString _f = fUrl;
+ QString _t = tUrl;
+ QString ex;
+ while (_f.endsWith("/")) {
+ _f.truncate(_f.length()-1);
+ }
+ while (_t.endsWith("/")) {
+ _t.truncate(_t.length()-1);
+ }
+ svn::Path p(path);
+ try {
+ StopDlg sdlg(m_Data->m_SvnContextListener,m_Data->m_ParentList->realWidget(),0,i18n("Relocate url"),i18n("Relocate repository to new URL"));
+ connect(this,SIGNAL(sigExtraLogMsg(const QString&)),&sdlg,SLOT(slotExtraMessage(const QString&)));
+ m_Data->m_Svnclient->relocate(p,_f,_t,rec);
+ } catch (const svn::Exception&e) {
+ emit clientException(e.msg());
+ return false;
+ }
+ EMIT_FINISHED;
+ return true;
+}
+
+void SvnActions::slotSwitch()
+{
+ if (!m_Data->m_CurrentContext) return;
+ if (!m_Data->m_ParentList||!m_Data->m_ParentList->isWorkingCopy()) return;
+
+ QPtrList<SvnItem> lst;
+ m_Data->m_ParentList->SelectionList(&lst);
+
+ if (lst.count()>1) {
+ KMessageBox::error(0,i18n("Can only switch one item at time"));
+ return;
+ }
+ SvnItem*k;
+
+ k = m_Data->m_ParentList->SelectedOrMain();
+ if (!k) {
+ KMessageBox::error(0,i18n("Error getting entry to switch"));
+ return;
+ }
+ QString path,what;
+ path = k->fullName();
+ what = k->Url();
+ if (makeSwitch(path,what)) {
+ emit reinitItem(k);
+ }
+}
+
+bool SvnActions::makeSwitch(const QString&path,const QString&what)
+{
+ CheckoutInfo_impl*ptr;
+ KDialogBase * dlg = createDialog(&ptr,i18n("Switch url"),true,"switch_url_dlg");
+ bool done = false;
+ if (dlg) {
+ ptr->setStartUrl(what);
+ ptr->disableAppend(true);
+ ptr->disableTargetDir(true);
+ ptr->disableOpen(true);
+ if (dlg->exec()==QDialog::Accepted) {
+ svn::Revision r = ptr->toRevision();
+ done = makeSwitch(ptr->reposURL(),path,r,ptr->getDepth(),r,true,ptr->ignoreExternals(),ptr->overwrite());
+ }
+ dlg->saveDialogSize(*(Kdesvnsettings::self()->config()),"switch_url_dlg",false);
+ delete dlg;
+ }
+ return done;
+}
+
+bool SvnActions::makeCleanup(const QString&path)
+{
+ if (!m_Data->m_CurrentContext) return false;
+ try {
+ StopDlg sdlg(m_Data->m_SvnContextListener,m_Data->m_ParentList->realWidget(),0,i18n("Cleanup"),i18n("Cleaning up folder"));
+ connect(this,SIGNAL(sigExtraLogMsg(const QString&)),&sdlg,SLOT(slotExtraMessage(const QString&)));
+ m_Data->m_Svnclient->cleanup(svn::Path(path));
+ } catch (const svn::Exception&e) {
+ emit clientException(e.msg());
+ return false;
+ }
+ return true;
+}
+
+void SvnActions::slotResolved(const QString&path)
+{
+ if (!m_Data->m_CurrentContext) return;
+ try {
+ StopDlg sdlg(m_Data->m_SvnContextListener,m_Data->m_ParentList->realWidget(),0,i18n("Resolve"),i18n("Marking resolved"));
+ connect(this,SIGNAL(sigExtraLogMsg(const QString&)),&sdlg,SLOT(slotExtraMessage(const QString&)));
+ m_Data->m_Svnclient->resolve(svn::Path(path),svn::DepthEmpty);
+ } catch (const svn::Exception&e) {
+ emit clientException(e.msg());
+ return;
+ }
+ m_Data->m_conflictCache.deleteKey(path,false);
+}
+
+void SvnActions::slotResolve(const QString&p)
+{
+ if (!m_Data->m_CurrentContext) return;
+ QString eresolv = Kdesvnsettings::conflict_resolver();
+ QStringList wlist = QStringList::split(" ",eresolv);
+ if (wlist.size()==0) {
+ return;
+ }
+ kdDebug()<<"Resolve: "<<p<<endl;
+ svn::InfoEntry i1;
+ if (!singleInfo(p,svn::Revision::UNDEFINED,i1)) {
+ return;
+ }
+ QFileInfo fi(p);
+ QString base = fi.dirPath(true);
+ kdDebug()<<i1.conflictNew()<<" "
+ <<i1.conflictOld()<<" "
+ <<i1.conflictWrk()<<" "
+ <<endl;
+ if (!i1.conflictNew().length()||
+ !i1.conflictOld().length()||
+ !i1.conflictWrk().length() ) {
+ emit sendNotify(i18n("Could not retrieve conflict information - giving up."));
+ return;
+ }
+
+ KProcess*proc = new KProcess();
+ for ( QStringList::Iterator it = wlist.begin();it!=wlist.end();++it) {
+ if (*it=="%o"||*it=="%l") {
+ *proc<<(base+"/"+i1.conflictOld());
+ } else if (*it=="%m" || *it=="%w") {
+ *proc<<(base+"/"+i1.conflictWrk());
+ } else if (*it=="%n"||*it=="%r") {
+ *proc<<(base+"/"+i1.conflictNew());
+ } else if (*it=="%t") {
+ *proc<<p;
+ } else {
+ *proc << *it;
+ }
+ }
+ connect(proc,SIGNAL(processExited(KProcess*)),this,SLOT(procClosed(KProcess*)));
+ connect(proc,SIGNAL(receivedStderr(KProcess*,char*,int)),this,SLOT(receivedStderr(KProcess*,char*,int)));
+ connect(proc,SIGNAL(receivedStdout(KProcess*,char*,int)),this,SLOT(receivedStderr(KProcess*,char*,int)));
+ if (proc->start(m_Data->runblocked?KProcess::Block:KProcess::NotifyOnExit,KProcess::All)) {
+ return;
+ } else {
+ emit sendNotify(i18n("Resolve-process could not started, check command."));
+ }
+ delete proc;
+ return;
+}
+
+void SvnActions::slotImport(const QString&path,const QString&target,const QString&message,svn::Depth depth,
+ bool noIgnore,bool noUnknown)
+{
+ if (!m_Data->m_CurrentContext) return;
+ try {
+ StopDlg sdlg(m_Data->m_SvnContextListener,m_Data->m_ParentList->realWidget(),0,i18n("Import"),i18n("Importing items"));
+ connect(this,SIGNAL(sigExtraLogMsg(const QString&)),&sdlg,SLOT(slotExtraMessage(const QString&)));
+ m_Data->m_Svnclient->import(svn::Path(path),target,message,depth,noIgnore,noUnknown);
+ } catch (const svn::Exception&e) {
+ emit clientException(e.msg());
+ return;
+ }
+}
+
+void SvnActions::slotMergeExternal(const QString&_src1,const QString&_src2, const QString&_target,
+ const svn::Revision&rev1,const svn::Revision&rev2,const svn::Revision&_peg,bool rec)
+{
+ KTempDir tdir1;
+ tdir1.setAutoDelete(true);
+ QString src1 = _src1;
+ QString src2 = _src2;
+ QString target = _target;
+ bool singleMerge = false;
+
+ if (rev1 == rev2 && (src2.isEmpty() || src1==src2) ) {
+ singleMerge = true;
+ }
+ if (src1.isEmpty()) {
+ emit clientException(i18n("Nothing to merge."));
+ return;
+ }
+ if (target.isEmpty()) {
+ emit clientException(i18n("No destination to merge."));
+ return;
+ }
+
+ KURL url(target);
+ if (!url.isLocalFile()) {
+ emit clientException(i18n("Target for merge must be local!"));
+ return;
+ }
+
+ QFileInfo f1(src1);
+ QFileInfo f2(src2);
+ bool isDir = true;
+
+ svn::InfoEntry i1,i2;
+
+ if (!singleInfo(src1,rev1,i1)) {
+ return;
+ }
+ isDir = i1.isDir();
+ if (!singleMerge && src1 != src2) {
+ if (!singleInfo(src2,rev2,i2)) {
+ return;
+ }
+ if (i2.isDir()!=isDir) {
+ emit clientException(i18n("Both sources must be same type!"));
+ return;
+ }
+ }
+
+ QFileInfo ti(target);
+
+ if (ti.isDir()!=isDir) {
+ emit clientException(i18n("Target for merge must same type like sources!"));
+ return;
+ }
+
+ QString s1 = f1.fileName()+"-"+rev1.toString();
+ QString s2 = f2.fileName()+"-"+rev2.toString();
+ QString first,second,out;
+ if (rev1 != svn::Revision::WORKING) {
+ first = tdir1.name()+"/"+s1;
+ } else {
+ first = src1;
+ }
+ if (!singleMerge) {
+ if (rev2!=svn::Revision::WORKING) {
+ second = tdir1.name()+"/"+s2;
+ } else {
+ second = src2;
+ }
+ } else {
+ // only two-way merge
+ second = QString::null;
+ }
+ if (second == first) {
+ KMessageBox::error(m_Data->m_ParentList->realWidget(),i18n("Both entries seems to be the same, won't do a merge."));
+ return;
+ }
+
+ if (rev1 != svn::Revision::WORKING) {
+ if (isDir) {
+ if (!makeCheckout(src1,first,rev1,svn::Revision::UNDEFINED,
+ rec?svn::DepthInfinity:svn::DepthFiles,
+ true,
+ false,
+ false,
+ false,0)) {
+ return;
+ }
+ } else {
+ if (!get(src1,first,rev1,svn::Revision::UNDEFINED,m_Data->m_ParentList->realWidget())) {
+ return;
+ }
+ }
+ }
+
+ if (!singleMerge) {
+ if (rev2!=svn::Revision::WORKING) {
+ if (isDir) {
+ if (!makeCheckout(src2,second,rev2,svn::Revision::UNDEFINED,
+ rec?svn::DepthInfinity:svn::DepthFiles,
+ true,false,false,false,0)) {
+ return;
+ }
+ } else {
+ if (!get(src2,second,rev2,svn::Revision::UNDEFINED,m_Data->m_ParentList->realWidget())) {
+ return;
+ }
+ }
+ }
+ }
+ QString edisp = Kdesvnsettings::external_merge_program();
+ QStringList wlist = QStringList::split(" ",edisp);
+ KProcess*proc = new KProcess();
+ for ( QStringList::Iterator it = wlist.begin();it!=wlist.end();++it) {
+ if (*it=="%s1") {
+ *proc<<first;
+ } else if (*it=="%s2") {
+ if (!second.isEmpty()) *proc<<second;
+ } else if (*it=="%t") {
+ *proc<<target;
+ } else {
+ *proc << *it;
+ }
+ }
+ connect(proc,SIGNAL(processExited(KProcess*)),this,SLOT(procClosed(KProcess*)));
+ connect(proc,SIGNAL(receivedStderr(KProcess*,char*,int)),this,SLOT(receivedStderr(KProcess*,char*,int)));
+ if (proc->start(m_Data->runblocked?KProcess::Block:KProcess::NotifyOnExit,KProcess::Stderr)) {
+ if (!m_Data->runblocked) {
+ tdir1.setAutoDelete(false);
+ m_Data->m_tempdirlist[proc].append(tdir1.name());
+ }
+ return;
+ } else {
+ emit sendNotify(i18n("Merge-process could not started, check command."));
+ }
+ delete proc;
+}
+
+void SvnActions::slotMergeWcRevisions(const QString&_entry,const svn::Revision&rev1,
+ const svn::Revision&rev2,
+ bool rec,bool ancestry,bool forceIt,bool dry)
+{
+ slotMerge(_entry,_entry,_entry,rev1,rev2,svn::Revision::UNDEFINED,rec,ancestry,forceIt,dry);
+}
+
+void SvnActions::slotMerge(const QString&src1,const QString&src2, const QString&target,
+ const svn::Revision&rev1,const svn::Revision&rev2,const svn::Revision&_peg,
+ bool rec,bool ancestry,bool forceIt,bool dry)
+{
+ if (!m_Data->m_CurrentContext) return;
+ QString s2;
+
+ svn::Revision peg = svn::Revision::HEAD;
+ svn::Revision tpeg;
+ svn::RevisionRanges ranges;
+ svn::Path p1;
+ try {
+ svn::Path::parsePeg(src1,p1,tpeg);
+ } catch (const svn::Exception&e) {
+ emit clientException(e.msg());
+ return;
+ }
+ if (tpeg!=svn::Revision::UNDEFINED) {
+ peg=tpeg;
+ }
+ svn::Path p2(src2);
+
+ bool pegged_merge=false;
+
+ if(!p2.isset() || src1==src2) {
+ // pegged merge
+ pegged_merge=true;
+ ranges.append(svn::RevisionRange(rev1,rev2));
+ if (peg==svn::Revision::UNDEFINED) {
+ if (p1.isUrl()) {
+ peg = rev2;
+ } else {
+ peg=svn::Revision::WORKING;
+ }
+ }
+ }
+ try {
+ StopDlg sdlg(m_Data->m_SvnContextListener,m_Data->m_ParentList->realWidget(),0,i18n("Merge"),i18n("Merging items"));
+ connect(this,SIGNAL(sigExtraLogMsg(const QString&)),&sdlg,SLOT(slotExtraMessage(const QString&)));
+ if (pegged_merge) {
+ m_Data->m_Svnclient->merge_peg(p1,ranges,svn::Revision::HEAD,svn::Path(target),rec?svn::DepthUnknown:svn::DepthFiles,
+ ancestry,dry,forceIt,false);
+ } else {
+ m_Data->m_Svnclient->merge(p1,rev1,p2,rev2,
+ svn::Path(target),
+ forceIt,rec?svn::DepthUnknown:svn::DepthFiles,ancestry,dry);
+ }
+ } catch (const svn::Exception&e) {
+ emit clientException(e.msg());
+ return;
+ }
+}
+
+/*!
+ \fn SvnActions::slotCopyMove(bool,const QString&,const QString&)
+ */
+bool SvnActions::makeMove(const QString&Old,const QString&New,bool force)
+{
+ if (!m_Data->m_CurrentContext) return false;
+ svn::Revision nnum;
+ try {
+ StopDlg sdlg(m_Data->m_SvnContextListener,m_Data->m_ParentList->realWidget(),0,i18n("Move"),i18n("Moving/Rename item "));
+ connect(this,SIGNAL(sigExtraLogMsg(const QString&)),&sdlg,SLOT(slotExtraMessage(const QString&)));
+ nnum = m_Data->m_Svnclient->move(svn::Path(Old),svn::Path(New),force);
+ } catch (const svn::Exception&e) {
+ emit clientException(e.msg());
+ return false;
+ }
+ if (nnum != svn::Revision::UNDEFINED) {
+ emit sendNotify(i18n("Committed revision %1.").arg(nnum.toString()));
+ }
+ EMIT_REFRESH;
+ return true;
+}
+
+bool SvnActions::makeMove(const KURL::List&Old,const QString&New,bool force)
+{
+ svn::Revision nnum;
+ try {
+ StopDlg sdlg(m_Data->m_SvnContextListener,m_Data->m_ParentList->realWidget(),0,i18n("Move"),i18n("Moving entries"));
+ connect(this,SIGNAL(sigExtraLogMsg(const QString&)),&sdlg,SLOT(slotExtraMessage(const QString&)));
+ KURL::List::ConstIterator it = Old.begin();
+ bool local = false;
+
+ if ((*it).protocol().isEmpty()) {
+ local = true;
+ }
+ it = Old.begin();
+ svn::Pathes p;
+ for (;it!=Old.end();++it) {
+ p.append((local?(*it).path():(*it).url()));
+ }
+ svn::Targets t(p);
+ svn::Path NPath(New);
+ m_Data->m_Svnclient->move(t,NPath,force,true,false);
+ } catch (const svn::Exception&e) {
+ emit clientException(e.msg());
+ return false;
+ }
+ return true;
+}
+
+bool SvnActions::makeCopy(const QString&Old,const QString&New,const svn::Revision&rev)
+{
+ if (!m_Data->m_CurrentContext) return false;
+ try {
+ StopDlg sdlg(m_Data->m_SvnContextListener,m_Data->m_ParentList->realWidget(),0,i18n("Copy / Move"),i18n("Copy or Moving entries"));
+ connect(this,SIGNAL(sigExtraLogMsg(const QString&)),&sdlg,SLOT(slotExtraMessage(const QString&)));
+ m_Data->m_Svnclient->copy(svn::Path(Old),rev,svn::Path(New));
+ } catch (const svn::Exception&e) {
+ emit clientException(e.msg());
+ return false;
+ }
+ EMIT_REFRESH;
+ return true;
+}
+
+bool SvnActions::makeCopy(const KURL::List&Old,const QString&New,const svn::Revision&rev)
+{
+ KURL::List::ConstIterator it = Old.begin();
+ svn::Pathes p;
+ bool local = false;
+ if ((*it).protocol().isEmpty()) {
+ local = true;
+ }
+ for (;it!=Old.end();++it) {
+ p.append((local?(*it).path():(*it).url()));
+ }
+ svn::Targets t(p);
+
+ try {
+ StopDlg sdlg(m_Data->m_SvnContextListener,m_Data->m_ParentList->realWidget(),0,i18n("Copy / Move"),i18n("Copy or Moving entries"));
+ connect(this,SIGNAL(sigExtraLogMsg(const QString&)),&sdlg,SLOT(slotExtraMessage(const QString&)));
+ KURL::List::ConstIterator it = Old.begin();
+ m_Data->m_Svnclient->copy(t,rev,rev,svn::Path(New),true);
+ } catch (const svn::Exception&e) {
+ emit clientException(e.msg());
+ return false;
+ }
+ return true;
+}
+
+/*!
+ \fn SvnActions::makeLock(const QStringList&)
+ */
+void SvnActions::makeLock(const QStringList&what,const QString&_msg,bool breakit)
+{
+ QValueList<svn::Path> targets;
+ for (unsigned int i = 0; i<what.count();++i) {
+ targets.push_back(svn::Path((*(what.at(i)))));
+ }
+ if (!m_Data->m_CurrentContext) return;
+ try {
+ m_Data->m_Svnclient->lock(svn::Targets(targets),_msg,breakit);
+ } catch (const svn::Exception&e) {
+ emit clientException(e.msg());
+ return;
+ }
+}
+
+
+/*!
+ \fn SvnActions::makeUnlock(const QStringList&)
+ */
+void SvnActions::makeUnlock(const QStringList&what,bool breakit)
+{
+ QValueList<svn::Path> targets;
+ if (!m_Data->m_CurrentContext) return;
+ for (unsigned int i = 0; i<what.count();++i) {
+ targets.push_back(svn::Path((*(what.at(i)))));
+ }
+
+ try {
+ m_Data->m_Svnclient->unlock(svn::Targets(targets),breakit);
+ } catch (const svn::Exception&e) {
+ emit clientException(e.msg());
+ return;
+ }
+ for (unsigned int i = 0; i<what.count();++i) {
+ m_Data->m_repoLockCache.deleteKey(*(what.at(i)),true);
+ }
+// m_Data->m_repoLockCache.dump_tree();
+}
+
+
+/*!
+ \fn SvnActions::makeStatus(const QString&what, svn::StatusEntries&dlist)
+ */
+bool SvnActions::makeStatus(const QString&what, svn::StatusEntries&dlist, svn::Revision&where,bool rec,bool all)
+{
+ bool display_ignores = Kdesvnsettings::display_ignored_files();
+ return makeStatus(what,dlist,where,rec,all,display_ignores);
+}
+
+bool SvnActions::makeStatus(const QString&what, svn::StatusEntries&dlist, svn::Revision&where,bool rec,bool all,bool display_ignores,bool updates)
+{
+ bool disp_remote_details = Kdesvnsettings::details_on_remote_listing();
+ QString ex;
+ svn::Depth _d=rec?svn::DepthInfinity:svn::DepthImmediates;
+ try {
+ StopDlg sdlg(m_Data->m_SvnContextListener,m_Data->m_ParentList->realWidget(),0,i18n("Status / List"),i18n("Creating list / check status"));
+ connect(this,SIGNAL(sigExtraLogMsg(const QString&)),&sdlg,SLOT(slotExtraMessage(const QString&)));
+ // rec all up noign
+ dlist = m_Data->m_Svnclient->status(what,_d,all,updates,display_ignores,where,disp_remote_details,false);
+ } catch (const svn::Exception&e) {
+ emit clientException(e.msg());
+ return false;
+ }
+ return true;
+}
+
+void SvnActions::checkAddItems(const QString&path,bool print_error_box)
+{
+ svn::StatusEntries dlist;
+ svn::StatusEntries rlist;
+ QStringList displist;
+ svn::Revision where = svn::Revision::HEAD;
+ if (!makeStatus(path,dlist,where,true,true,false,false)) {
+ return;
+ }
+ for (unsigned int i = 0; i<dlist.size();++i) {
+ if (!dlist[i]->isVersioned()) {
+ rlist.append(dlist[i]);
+ displist.append(dlist[i]->path());
+ }
+ }
+ if (rlist.size()==0) {
+ if (print_error_box) KMessageBox::error(m_Data->m_ParentList->realWidget(),i18n("No unversioned items found."));
+ } else {
+ KListView*ptr;
+ KDialogBase * dlg = createDialog(&ptr,i18n("Add unversioned items"),true,"add_items_dlg");
+ ptr->addColumn("Item");
+ for (unsigned j = 0; j<displist.size();++j) {
+ QCheckListItem * n = new QCheckListItem(ptr,displist[j],QCheckListItem::CheckBox);
+ n->setOn(true);
+ }
+ if (dlg->exec()==QDialog::Accepted) {
+ QListViewItemIterator it(ptr);
+ displist.clear();
+ while(it.current()) {
+ QCheckListItem*t = (QCheckListItem*)it.current();
+ if (t->isOn()) {
+ displist.append(t->text());
+ }
+ ++it;
+ }
+ if (displist.count()>0) {
+ addItems(displist,svn::DepthEmpty);
+ }
+ }
+ dlg->saveDialogSize(*(Kdesvnsettings::self()->config()),"add_items_dlg",false);
+ delete dlg;
+ }
+}
+
+void SvnActions::stopCheckModThread()
+{
+ m_Data->m_ThreadCheckTimer.stop();
+ if (m_CThread) {
+ m_CThread->cancelMe();
+ if (!m_CThread->wait(MAX_THREAD_WAITTIME)) {
+ m_CThread->terminate();
+ m_CThread->wait(MAX_THREAD_WAITTIME);
+ }
+ delete m_CThread;
+ m_CThread=0;
+ }
+}
+
+void SvnActions::stopCheckUpdateThread()
+{
+ m_Data->m_UpdateCheckTimer.stop();
+ if (m_UThread) {
+ m_UThread->cancelMe();
+ if (!m_UThread->wait(MAX_THREAD_WAITTIME)) {
+ m_UThread->terminate();
+ m_UThread->wait(MAX_THREAD_WAITTIME);
+ }
+ delete m_UThread;
+ m_UThread=0;
+ }
+}
+
+void SvnActions::stopFillCache()
+{
+ if (m_FCThread) {
+ m_FCThread->cancelMe();
+ if (!m_FCThread->wait(MAX_THREAD_WAITTIME)) {
+ m_FCThread->terminate();
+ m_FCThread->wait(MAX_THREAD_WAITTIME);
+ }
+ delete m_FCThread;
+ m_FCThread = 0;
+ emit sigCacheStatus(-1,-1);
+ }
+}
+
+void SvnActions::stopMain()
+{
+ if (m_Data->m_CurrentContext) {
+ m_Data->m_SvnContextListener->setCanceled(true);
+ sleep(1);
+ m_Data->m_SvnContextListener->contextCancel();
+ }
+}
+
+void SvnActions::killallThreads()
+{
+ stopMain();
+ stopCheckModThread();
+ stopCheckUpdateThread();
+ stopFillCache();
+}
+
+bool SvnActions::createModifiedCache(const QString&what)
+{
+ stopCheckModThread();
+ m_Data->m_Cache.clear();
+ m_Data->m_conflictCache.clear();
+ kdDebug()<<"Create cache for " << what << endl;
+ m_CThread = new CheckModifiedThread(this,what);
+ m_CThread->start();
+ m_Data->m_ThreadCheckTimer.start(100,true);
+ return true;
+}
+
+void SvnActions::checkModthread()
+{
+ if (!m_CThread)return;
+ if (m_CThread->running()) {
+ m_Data->m_ThreadCheckTimer.start(100,true);
+ return;
+ }
+ kdDebug()<<"ModifiedThread seems stopped"<<endl;
+ for (unsigned int i = 0; i < m_CThread->getList().count();++i) {
+ svn::StatusPtr ptr = m_CThread->getList()[i];
+ if (m_CThread->getList()[i]->isRealVersioned()&& (
+ m_CThread->getList()[i]->textStatus()==svn_wc_status_modified||
+ m_CThread->getList()[i]->textStatus()==svn_wc_status_added||
+ m_CThread->getList()[i]->textStatus()==svn_wc_status_deleted||
+ m_CThread->getList()[i]->textStatus()==svn_wc_status_replaced||
+ m_CThread->getList()[i]->propStatus()==svn_wc_status_modified
+ ) ) {
+ m_Data->m_Cache.insertKey(ptr,ptr->path());
+ } else if (m_CThread->getList()[i]->textStatus()==svn_wc_status_conflicted) {
+ m_Data->m_conflictCache.insertKey(ptr,ptr->path());
+ }
+ }
+ delete m_CThread;
+ m_CThread = 0;
+ emit sigRefreshIcons(false);
+}
+
+void SvnActions::checkUpdateThread()
+{
+ if (!m_UThread)return;
+ if (m_UThread->running()) {
+ if (m_Data->m_UpdateCheckTick.elapsed()>2500) {
+ m_Data->m_UpdateCheckTick.restart();
+ emit sendNotify(i18n("Still checking for updates"));
+ }
+ m_Data->m_UpdateCheckTimer.start(100,true);
+ return;
+ }
+ kdDebug()<<"Updates Thread seems stopped"<<endl;
+
+ bool newer=false;
+ for (unsigned int i = 0; i < m_UThread->getList().count();++i) {
+ svn::StatusPtr ptr = m_UThread->getList()[i];
+ if (ptr->validReposStatus()) {
+ m_Data->m_UpdateCache.insertKey(ptr,ptr->path());
+ ptr->textStatus();
+ ptr->propStatus();
+ if (!(ptr->validLocalStatus())) {
+ newer = true;
+ }
+ }
+ if (ptr->isLocked() &&
+ !(ptr->entry().lockEntry().Locked())) {
+ m_Data->m_repoLockCache.insertKey(ptr,ptr->path());
+ }
+ }
+ emit sigRefreshIcons(newer);
+ emit sendNotify(i18n("Checking for updates finished"));
+ if (newer) {
+ emit sendNotify(i18n("There are new items in repository"));
+ }
+ delete m_UThread;
+ m_UThread = 0;
+}
+
+void SvnActions::getaddedItems(const QString&path,svn::StatusEntries&target)
+{
+ helpers::ValidRemoteOnly vro;
+ m_Data->m_UpdateCache.listsubs_if(path,vro);
+ target=vro.liste();
+}
+
+bool SvnActions::checkUpdatesRunning()
+{
+ return m_UThread && m_UThread->running();
+}
+
+void SvnActions::addModifiedCache(const svn::StatusPtr&what)
+{
+ if (what->textStatus()==svn_wc_status_conflicted) {
+ m_Data->m_conflictCache.insertKey(what,what->path());
+ } else {
+ m_Data->m_Cache.insertKey(what,what->path());
+// m_Data->m_Cache.dump_tree();
+ }
+}
+
+void SvnActions::deleteFromModifiedCache(const QString&what)
+{
+ m_Data->m_Cache.deleteKey(what,true);
+ m_Data->m_conflictCache.deleteKey(what,true);
+ //m_Data->m_Cache.dump_tree();
+}
+
+bool SvnActions::checkModifiedCache(const QString&path)
+{
+ return m_Data->m_Cache.find(path);
+}
+
+bool SvnActions::checkReposLockCache(const QString&path)
+{
+ return m_Data->m_repoLockCache.findSingleValid(path,false);
+}
+
+bool SvnActions::checkReposLockCache(const QString&path,svn::SharedPointer<svn::Status>&t)
+{
+ /// @todo create a method where svn::Status* will be a parameter so no copy is needed but just reading content
+ return m_Data->m_repoLockCache.findSingleValid(path,t);
+}
+
+bool SvnActions::checkConflictedCache(const QString&path)
+{
+ return m_Data->m_conflictCache.find(path);
+}
+
+void SvnActions::startFillCache(const QString&path)
+{
+ stopFillCache();
+ svn::InfoEntry e;
+ if (!doNetworking()) {
+ emit sendNotify(i18n("Not filling logcache because networking is disabled"));
+ return;
+ }
+ if (!singleInfo(path,svn::Revision::UNDEFINED,e)) {
+ return;
+ }
+ if (svn::Url::isLocal(e.reposRoot())) {
+ return;
+ }
+ m_FCThread=new FillCacheThread(this,e.reposRoot());
+ m_FCThread->start();
+ emit sendNotify(i18n("Filling log cache in background"));
+}
+
+bool SvnActions::doNetworking()
+{
+ // if networking is allowd we don't need extra checks, second is just for avoiding segfaults
+ if (Kdesvnsettings::network_on()||!m_Data->m_ParentList) {
+ return true;
+ }
+ bool is_url=false;
+ if (m_Data->m_ParentList->isNetworked()) {
+ // if called http:// etc.pp.
+ is_url=true;
+ } else if (m_Data->m_ParentList->baseUri().startsWith("/")){
+ // if opened a working copy we must check if it points to a networking repository
+ svn::InfoEntry e;
+ if (!singleInfo(m_Data->m_ParentList->baseUri(),svn::Revision::UNDEFINED,e)) {
+ return false;
+ }
+ is_url = !e.reposRoot().startsWith("file:/");
+ }
+ return !is_url;
+}
+
+void SvnActions::customEvent(QCustomEvent * e)
+{
+ if (e->type()==EVENT_LOGCACHE_FINISHED) {
+ emit sendNotify(i18n("Filling log cache in background finished."));
+ stopFillCache();
+ emit sigThreadsChanged();
+ return;
+ } else if (e&&e->type()==EVENT_LOGCACHE_STATUS && m_FCThread && m_FCThread->running()) {
+ FillCacheStatusEvent*fev=(FillCacheStatusEvent*)e;
+ emit sigCacheStatus(fev->current(),fev->max());
+ }
+}
+
+/*!
+ \fn SvnActions::createUpdateCache(const QString&what)
+ */
+bool SvnActions::createUpdateCache(const QString&what)
+{
+ clearUpdateCache();
+ m_Data->m_repoLockCache.clear();
+ stopCheckUpdateThread();
+ if (!doNetworking()) {
+ emit sendNotify(i18n("Not checking for updates because networking is disabled"));
+ return false;
+ }
+
+ m_UThread = new CheckModifiedThread(this,what,true);
+ m_UThread->start();
+ m_Data->m_UpdateCheckTimer.start(100,true);
+ emit sendNotify(i18n("Checking for updates started in background"));
+ m_Data->m_UpdateCheckTick.start();
+ return true;
+}
+
+bool SvnActions::checkUpdateCache(const QString&path)const
+{
+ return m_Data->m_UpdateCache.find(path);
+}
+
+void SvnActions::removeFromUpdateCache(const QStringList&what,bool exact_only)
+{
+ for (unsigned int i = 0; i < what.count(); ++i) {
+ m_Data->m_UpdateCache.deleteKey(what[i],exact_only);
+ }
+}
+
+bool SvnActions::isUpdated(const QString&path)const
+{
+ svn::SharedPointer<svn::Status> d;
+ return m_Data->m_UpdateCache.findSingleValid(path,d);
+}
+
+bool SvnActions::getUpdated(const QString&path,svn::SharedPointer<svn::Status>&d)const
+{
+ return m_Data->m_UpdateCache.findSingleValid(path,d);
+}
+
+void SvnActions::clearUpdateCache()
+{
+ m_Data->m_UpdateCache.clear();
+}
+
+/*!
+ \fn SvnActions::makeIgnoreEntry(const QString&which)
+ */
+bool SvnActions::makeIgnoreEntry(SvnItem*which,bool unignore)
+{
+ if (!which) return false;
+ QString parentName = which->getParentDir();
+ if (parentName.isEmpty()) return false;
+ QString name = which->shortName();
+ QString ex;
+ svn::Path p(parentName);
+ svn::Revision r(svn_opt_revision_unspecified);
+
+ QPair<QLONG,svn::PathPropertiesMapList> pmp;
+ try {
+ pmp = m_Data->m_Svnclient->propget("svn:ignore",p,r,r);
+ } catch (const svn::Exception&e) {
+ emit clientException(e.msg());
+ return false;
+ }
+ svn::PathPropertiesMapList pm = pmp.second;
+ QString data = "";
+ if (pm.size()>0) {
+ svn::PropertiesMap&mp = pm[0].second;
+ data = mp["svn:ignore"];
+ }
+ bool result = false;
+ QStringList lst = QStringList::split("\n",data);
+ QStringList::iterator it = lst.find(name);
+ if (it != lst.end()) {
+ if (unignore) {
+ lst.erase(it);
+ result = true;
+ }
+ } else {
+ if (!unignore) {
+ lst.append(name);
+ result = true;
+ }
+ }
+ if (result) {
+ data = lst.join("\n");
+ try {
+ m_Data->m_Svnclient->propset("svn:ignore",data,p);
+ } catch (const svn::Exception&e) {
+ emit clientException(e.msg());
+ return false;
+ }
+ }
+ return result;
+}
+
+svn::PathPropertiesMapListPtr SvnActions::propList(const QString&which,const svn::Revision&where,bool cacheOnly)
+{
+ svn::PathPropertiesMapListPtr pm;
+ if (!which.isEmpty()) {
+ QString fk=where.toString()+"/"+which;
+ QString ex;
+ svn::Path p(which);
+
+ if (where != svn::Revision::WORKING)
+ {
+ m_Data->m_PropertiesCache.findSingleValid(fk,pm);
+ }
+ if (!pm && !cacheOnly)
+ {
+ try {
+ pm = m_Data->m_Svnclient->proplist(p,where,where);
+ } catch (const svn::Exception&e) {
+ /* no messagebox needed */
+ if (e.apr_err()!=SVN_ERR_WC_NOT_DIRECTORY) {
+ sendNotify(e.msg());
+ }
+ }
+ if (where != svn::Revision::WORKING && pm) {
+ kdDebug()<<"Put into cache "<<endl;
+ m_Data->m_PropertiesCache.insertKey(pm,fk);
+ }
+ }
+ }
+ return pm;
+}
+
+bool SvnActions::isLockNeeded(SvnItem*which,const svn::Revision&where)
+{
+ if (!which) return false;
+ QString ex;
+ svn::Path p(which->fullName());
+
+ QPair<QLONG,svn::PathPropertiesMapList> pmp;
+ try {
+ pmp = m_Data->m_Svnclient->propget("svn:needs-lock",p,where,where);
+ } catch (const svn::Exception&e) {
+ /* no messagebox needed */
+ //emit clientException(e.msg());
+ return false;
+ }
+ svn::PathPropertiesMapList pm = pmp.second;
+ if (pm.size()>0) {
+ svn::PropertiesMap&mp = pm[0].second;
+ if (mp.find("svn:needs-lock")!=mp.end()) {
+ return true;
+ }
+ }
+ return false;
+}
+
+QString SvnActions::searchProperty(QString&Store, const QString&property, const QString&start,const svn::Revision&where,bool up)
+{
+ svn::Path pa(start);
+ kdDebug()<<"Url? "<<pa.isUrl()<<endl;
+ svn::InfoEntry inf;
+
+ if (!singleInfo(start,where,inf)) {
+ return QString::null;
+ }
+ while(pa.length()>0) {
+ svn::PathPropertiesMapListPtr pm = propList(pa,where,false);
+ if (!pm) {
+ return QString::null;
+ }
+ if (pm->size()>0) {
+ svn::PropertiesMap&mp = (*pm)[0].second;
+ if (mp.find(property)!=mp.end()) {
+ Store=mp[property];
+ return pa;
+ }
+ }
+ if (up) {
+ pa.removeLast();
+ kdDebug()<<"Going up to " << pa.path() << endl;
+ if (pa.isUrl() && inf.reposRoot().length()>pa.path().length()) {
+ kdDebug()<<pa.path()<<" is not in repository" << endl;
+ break;
+ }
+
+ } else {
+ break;
+ }
+ }
+ return QString::null;
+}
+
+bool SvnActions::makeList(const QString&url,svn::DirEntries&dlist,svn::Revision&where,bool rec)
+{
+ if (!m_Data->m_CurrentContext) return false;
+ QString ex;
+ try {
+ dlist = m_Data->m_Svnclient->list(url,where,where,rec?svn::DepthInfinity:svn::DepthEmpty,false);
+ } catch (const svn::Exception&e) {
+ emit clientException(e.msg());
+ return false;
+ }
+ return true;
+}
+
+/*!
+ \fn SvnActions::isLocalWorkingCopy(const KURL&url)
+ */
+bool SvnActions::isLocalWorkingCopy(const KURL&url,QString&_baseUri)
+{
+ if (url.isEmpty()||!url.isLocalFile()) return false;
+ QString cleanpath = url.path();
+ while (cleanpath.endsWith("/")) {
+ cleanpath.truncate(cleanpath.length()-1);
+ }
+ _baseUri="";
+ svn::Revision peg(svn_opt_revision_unspecified);
+ svn::Revision rev(svn_opt_revision_unspecified);
+ svn::InfoEntries e;
+ try {
+ e = m_Data->m_Svnclient->info(cleanpath,svn::DepthEmpty,rev,peg);
+ } catch (const svn::Exception&e) {
+ kdDebug()<< e.msg()<< " " << endl;
+ if (SVN_ERR_WC_NOT_DIRECTORY==e.apr_err())
+ {
+ return false;
+ }
+ return true;
+ }
+ _baseUri=e[0].url();
+ return true;
+}
+
+void SvnActions::slotExtraLogMsg(const QString&msg)
+{
+ emit sigExtraLogMsg(msg);
+}
+
+void SvnActions::slotCancel(bool how)
+{
+ if (!m_Data->m_CurrentContext) return;
+ m_Data->m_SvnContextListener->setCanceled(how);
+}
+
+void SvnActions::setContextData(const QString&aKey,const QString&aValue)
+{
+ if (aValue.isNull()) {
+ QMap<QString,QString>::iterator it = m_Data->m_contextData.find(aKey);
+ if (it!=m_Data->m_contextData.end()) {
+ m_Data->m_contextData.remove(it);
+ }
+ } else {
+ m_Data->m_contextData[aKey]=aValue;
+ }
+}
+
+void SvnActions::clearContextData()
+{
+ m_Data->m_contextData.clear();
+}
+
+QString SvnActions::getContextData(const QString&aKey)const
+{
+ if (m_Data->m_contextData.find(aKey)!=m_Data->m_contextData.end()) {
+ return m_Data->m_contextData[aKey];
+ }
+ return QString::null;
+}
+
+bool SvnActions::threadRunning(ThreadType which)
+{
+ switch(which) {
+ case checkupdatethread:
+ return (m_UThread && m_UThread->running());
+ break;
+ case fillcachethread:
+ return (m_FCThread && m_FCThread->running());
+ break;
+ case checkmodifiedthread:
+ return (m_CThread && m_CThread->running());
+ break;
+ }
+ return false;
+}
+
+#include "svnactions.moc"