katedocmanager.cpp

00001 /* This file is part of the KDE project
00002    Copyright (C) 2001 Christoph Cullmann <cullmann@kde.org>
00003    Copyright (C) 2002 Joseph Wenninger <jowenn@kde.org>
00004 
00005    This library is free software; you can redistribute it and/or
00006    modify it under the terms of the GNU Library General Public
00007    License version 2 as published by the Free Software Foundation.
00008 
00009    This library is distributed in the hope that it will be useful,
00010    but WITHOUT ANY WARRANTY; without even the implied warranty of
00011    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012    Library General Public License for more details.
00013 
00014    You should have received a copy of the GNU Library General Public License
00015    along with this library; see the file COPYING.LIB.  If not, write to
00016    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00017    Boston, MA 02110-1301, USA.
00018 */
00019 
00020 #include "katedocmanager.h"
00021 #include "katedocmanager.moc"
00022 #include "kateapp.h"
00023 #include "katemainwindow.h"
00024 #include "kateviewmanager.h"
00025 #include "katedocmanageriface.h"
00026 #include "kateexternaltools.h"
00027 #include "kateviewspacecontainer.h"
00028 
00029 #include <kate/view.h>
00030 
00031 #include <ktexteditor/encodinginterface.h>
00032 
00033 #include <kparts/factory.h>
00034 
00035 #include <klocale.h>
00036 #include <kdebug.h>
00037 #include <kconfig.h>
00038 #include <klibloader.h>
00039 #include <kmdcodec.h>
00040 #include <kmessagebox.h>
00041 #include <kencodingfiledialog.h>
00042 
00043 #include <qdatetime.h>
00044 #include <qtextcodec.h>
00045 #include <qprogressdialog.h>
00046 
00047 KateDocManager::KateDocManager (QObject *parent)
00048  : QObject (parent)
00049  , m_saveMetaInfos(true)
00050  , m_daysMetaInfos(0)
00051 {
00052   m_factory = (KParts::Factory *) KLibLoader::self()->factory ("libkatepart");
00053 
00054   m_documentManager = new Kate::DocumentManager (this);
00055   m_docList.setAutoDelete(true);
00056   m_docDict.setAutoDelete(false);
00057   m_docInfos.setAutoDelete(true);
00058 
00059   m_dcop = new KateDocManagerDCOPIface (this);
00060 
00061   m_metaInfos = new KConfig("metainfos", false, false, "appdata");
00062 
00063   createDoc ();
00064 }
00065 
00066 KateDocManager::~KateDocManager ()
00067 {
00068   // save config
00069   if (!m_docList.isEmpty())
00070     m_docList.at(0)->writeConfig(KateApp::self()->config());
00071 
00072   if (m_saveMetaInfos)
00073   {
00074     // saving meta-infos when file is saved is not enough, we need to do it once more at the end
00075     for (Kate::Document *doc = m_docList.first(); doc; doc = m_docList.next())
00076       saveMetaInfos(doc);
00077 
00078     // purge saved filesessions
00079     if (m_daysMetaInfos > 0)
00080     {
00081       QStringList groups = m_metaInfos->groupList();
00082       QDateTime *def = new QDateTime(QDate(1970, 1, 1));
00083       for (QStringList::Iterator it = groups.begin(); it != groups.end(); ++it)
00084       {
00085         m_metaInfos->setGroup(*it);
00086         QDateTime last = m_metaInfos->readDateTimeEntry("Time", def);
00087         if (last.daysTo(QDateTime::currentDateTime()) > m_daysMetaInfos)
00088           m_metaInfos->deleteGroup(*it);
00089       }
00090       delete def;
00091     }
00092   }
00093 
00094   delete m_dcop;
00095   delete m_metaInfos;
00096 }
00097 
00098 KateDocManager *KateDocManager::self ()
00099 {
00100   return KateApp::self()->documentManager ();
00101 }
00102 
00103 Kate::Document *KateDocManager::createDoc ()
00104 {
00105   KTextEditor::Document *doc = (KTextEditor::Document *) m_factory->createPart (0, "", this, "", "KTextEditor::Document");
00106 
00107   m_docList.append((Kate::Document *)doc);
00108   m_docDict.insert (doc->documentNumber(), (Kate::Document *)doc);
00109   m_docInfos.insert (doc, new KateDocumentInfo ());
00110 
00111   if (m_docList.count() < 2)
00112     ((Kate::Document *)doc)->readConfig(KateApp::self()->config());
00113 
00114   emit documentCreated ((Kate::Document *)doc);
00115   emit m_documentManager->documentCreated ((Kate::Document *)doc);
00116 
00117   connect(doc,SIGNAL(modifiedOnDisc(Kate::Document *, bool, unsigned char)),this,SLOT(slotModifiedOnDisc(Kate::Document *, bool, unsigned char)));
00118   return (Kate::Document *)doc;
00119 }
00120 
00121 void KateDocManager::deleteDoc (Kate::Document *doc)
00122 {
00123   uint id = doc->documentNumber();
00124   uint activeId = 0;
00125   if (m_currentDoc)
00126     activeId = m_currentDoc->documentNumber ();
00127 
00128   if (m_docList.count() < 2)
00129     doc->writeConfig(KateApp::self()->config());
00130 
00131   m_docInfos.remove (doc);
00132   m_docDict.remove (id);
00133   m_docList.remove (doc);
00134 
00135   emit documentDeleted (id);
00136   emit m_documentManager->documentDeleted (id);
00137 
00138   // ohh, current doc was deleted
00139   if (activeId == id)
00140   {
00141     // special case of documentChanged, no longer any doc here !
00142     m_currentDoc = 0;
00143 
00144     emit documentChanged ();
00145     emit m_documentManager->documentChanged ();
00146   }
00147 }
00148 
00149 Kate::Document *KateDocManager::document (uint n)
00150 {
00151   return m_docList.at(n);
00152 }
00153 
00154 Kate::Document *KateDocManager::activeDocument ()
00155 {
00156   return m_currentDoc;
00157 }
00158 
00159 void KateDocManager::setActiveDocument (Kate::Document *doc)
00160 {
00161   if (!doc)
00162     return;
00163 
00164   if (m_currentDoc && (m_currentDoc->documentNumber() == doc->documentNumber()))
00165     return;
00166 
00167   m_currentDoc = doc;
00168 
00169   emit documentChanged ();
00170   emit m_documentManager->documentChanged ();
00171 }
00172 
00173 Kate::Document *KateDocManager::firstDocument ()
00174 {
00175   return m_docList.first();
00176 }
00177 
00178 Kate::Document *KateDocManager::nextDocument ()
00179 {
00180   return m_docList.next();
00181 }
00182 
00183 Kate::Document *KateDocManager::documentWithID (uint id)
00184 {
00185   return m_docDict[id];
00186 }
00187 
00188 const KateDocumentInfo *KateDocManager::documentInfo (Kate::Document *doc)
00189 {
00190   return m_docInfos[doc];
00191 }
00192 
00193 int KateDocManager::findDocument (Kate::Document *doc)
00194 {
00195   return m_docList.find (doc);
00196 }
00197 
00198 uint KateDocManager::documents ()
00199 {
00200   return m_docList.count ();
00201 }
00202 
00203 int KateDocManager::findDocument ( KURL url )
00204 {
00205   QPtrListIterator<Kate::Document> it(m_docList);
00206 
00207   for (; it.current(); ++it)
00208   {
00209     if ( it.current()->url() == url)
00210       return it.current()->documentNumber();
00211   }
00212   return -1;
00213 }
00214 
00215 Kate::Document *KateDocManager::findDocumentByUrl( KURL url )
00216 {
00217   for (QPtrListIterator<Kate::Document> it(m_docList); it.current(); ++it)
00218   {
00219     if ( it.current()->url() == url)
00220       return it.current();
00221   }
00222 
00223   return 0L;
00224 }
00225 
00226 bool KateDocManager::isOpen(KURL url)
00227 {
00228   // return just if we found some document with this url
00229   return findDocumentByUrl (url) != 0;
00230 }
00231 
00232 Kate::Document *KateDocManager::openURL (const KURL& url,const QString &encoding, uint *id)
00233 {
00234   // special handling if still only the first initial doc is there
00235   if (!documentList().isEmpty() && (documentList().count() == 1) && (!documentList().at(0)->isModified() && documentList().at(0)->url().isEmpty()))
00236   {
00237     Kate::Document* doc = documentList().getFirst();
00238 
00239     doc->setEncoding(encoding);
00240 
00241     if (!loadMetaInfos(doc, url))
00242       doc->openURL (url);
00243 
00244     if (id)
00245       *id=doc->documentNumber();
00246 
00247     connect(doc, SIGNAL(modStateChanged(Kate::Document *)), this, SLOT(slotModChanged(Kate::Document *)));
00248 
00249     emit initialDocumentReplaced();
00250 
00251     return doc;
00252  }
00253 
00254   Kate::Document *doc = findDocumentByUrl (url);
00255   if ( !doc )
00256   {
00257     doc = (Kate::Document *)createDoc ();
00258 
00259     doc->setEncoding(encoding.isNull() ? Kate::Document::defaultEncoding() : encoding);
00260 
00261     if (!loadMetaInfos(doc, url))
00262       doc->openURL (url);
00263   }
00264 
00265   if (id)
00266     *id=doc->documentNumber();
00267 
00268   return doc;
00269 }
00270 
00271 bool KateDocManager::closeDocument(class Kate::Document *doc,bool closeURL)
00272 {
00273   if (!doc) return false;
00274 
00275   saveMetaInfos(doc);
00276   if (closeURL)
00277   if (!doc->closeURL()) return false;
00278 
00279   QPtrList<Kate::View> closeList;
00280   uint documentNumber = doc->documentNumber();
00281 
00282   for (uint i=0; i < KateApp::self()->mainWindows (); i++ )
00283   {
00284     KateApp::self()->mainWindow(i)->viewManager()->closeViews(documentNumber);
00285   }
00286 
00287   deleteDoc (doc);
00288 
00289   // never ever empty the whole document list
00290   if (m_docList.isEmpty())
00291     createDoc ();
00292 
00293   return true;
00294 }
00295 
00296 bool KateDocManager::closeDocument(uint n)
00297 {
00298   return closeDocument(document(n));
00299 }
00300 
00301 bool KateDocManager::closeDocumentWithID(uint id)
00302 {
00303   return closeDocument(documentWithID(id));
00304 }
00305 
00306 bool KateDocManager::closeAllDocuments(bool closeURL)
00307 {
00308   bool res = true;
00309 
00310   QPtrList<Kate::Document> docs = m_docList;
00311 
00312   for (uint i=0; i < KateApp::self()->mainWindows (); i++ )
00313   {
00314     KateApp::self()->mainWindow(i)->viewManager()->setViewActivationBlocked(true);
00315   }
00316 
00317   while (!docs.isEmpty() && res)
00318     if (! closeDocument(docs.at(0),closeURL) )
00319       res = false;
00320     else
00321       docs.remove ((uint)0);
00322 
00323   for (uint i=0; i < KateApp::self()->mainWindows (); i++ )
00324   {
00325     KateApp::self()->mainWindow(i)->viewManager()->setViewActivationBlocked(false);
00326 
00327     for (uint s=0; s < KateApp::self()->mainWindow(i)->viewManager()->containers()->count(); s++)
00328       KateApp::self()->mainWindow(i)->viewManager()->containers()->at(s)->activateView (m_docList.at(0)->documentNumber());
00329   }
00330 
00331   return res;
00332 }
00333 
00334 QPtrList<Kate::Document> KateDocManager::modifiedDocumentList() {
00335   QPtrList<Kate::Document> modified;
00336   for (QPtrListIterator<Kate::Document> it(m_docList); it.current(); ++it) {
00337     Kate::Document *doc = it.current();
00338     if (doc->isModified()) {
00339       modified.append(doc);
00340     }
00341   }
00342   return modified;
00343 }
00344 
00345 
00346 bool KateDocManager::queryCloseDocuments(KateMainWindow *w)
00347 {
00348   uint docCount = m_docList.count();
00349   for (QPtrListIterator<Kate::Document> it(m_docList); it.current(); ++it)
00350   {
00351     Kate::Document *doc = it.current();
00352 
00353     if (doc->url().isEmpty() && doc->isModified())
00354     {
00355       int msgres=KMessageBox::warningYesNoCancel( w,
00356                   i18n("<p>The document '%1' has been modified, but not saved."
00357                        "<p>Do you want to save your changes or discard them?").arg( doc->docName() ),
00358                     i18n("Close Document"), KStdGuiItem::save(), KStdGuiItem::discard() );
00359 
00360       if (msgres==KMessageBox::Cancel)
00361         return false;
00362 
00363       if (msgres==KMessageBox::Yes)
00364       {
00365         KEncodingFileDialog::Result r=KEncodingFileDialog::getSaveURLAndEncoding(
00366               KTextEditor::encodingInterface(doc)->encoding(),QString::null,QString::null,w,i18n("Save As"));
00367 
00368         doc->setEncoding( r.encoding );
00369 
00370         if (!r.URLs.isEmpty())
00371         {
00372           KURL tmp = r.URLs.first();
00373 
00374           if ( !doc->saveAs( tmp ) )
00375             return false;
00376         }
00377         else
00378           return false;
00379       }
00380     }
00381     else
00382     {
00383       if (!doc->queryClose())
00384         return false;
00385     }
00386   }
00387 
00388   // document count changed while queryClose, abort and notify user
00389   if (m_docList.count() > docCount)
00390   {
00391     KMessageBox::information (w,
00392                           i18n ("New file opened while trying to close Kate, closing aborted."),
00393                           i18n ("Closing Aborted"));
00394     return false;
00395   }
00396 
00397   return true;
00398 }
00399 
00400 
00401 void KateDocManager::saveAll()
00402 {
00403   for (QPtrListIterator<Kate::Document> it(m_docList); it.current(); ++it)
00404     if ( it.current()->isModified() && it.current()->views().count() )
00405       ((Kate::View*)it.current()->views().first())->save();
00406 }
00407 
00408 void KateDocManager::saveDocumentList (KConfig* config)
00409 {
00410   QString prevGrp=config->group();
00411   config->setGroup ("Open Documents");
00412   QString grp = config->group();
00413 
00414   config->writeEntry ("Count", m_docList.count());
00415 
00416   int i=0;
00417   for ( Kate::Document *doc = m_docList.first(); doc; doc = m_docList.next() )
00418   {
00419     config->setGroup(QString("Document %1").arg(i));
00420     doc->writeSessionConfig(config);
00421     config->setGroup(grp);
00422 
00423     i++;
00424   }
00425 
00426   config->setGroup(prevGrp);
00427 }
00428 
00429 void KateDocManager::restoreDocumentList (KConfig* config)
00430 {
00431   QString prevGrp=config->group();
00432   config->setGroup ("Open Documents");
00433   QString grp = config->group();
00434 
00435   unsigned int count = config->readUnsignedNumEntry("Count", 0);
00436 
00437   if (count == 0)
00438   {
00439     config->setGroup(prevGrp);
00440     return;
00441   }
00442 
00443   QProgressDialog *pd=new QProgressDialog(
00444         i18n("Reopening files from the last session..."),
00445         QString::null,
00446         count,
00447         0,
00448         "openprog");
00449 
00450   pd->setCaption (KateApp::self()->makeStdCaption(i18n("Starting Up")));
00451 
00452   bool first = true;
00453   for (unsigned int i=0; i < count; i++)
00454   {
00455     config->setGroup(QString("Document %1").arg(i));
00456     Kate::Document *doc = 0;
00457 
00458     if (first)
00459     {
00460       first = false;
00461       doc = document (0);
00462     }
00463     else
00464       doc = createDoc ();
00465 
00466     doc->readSessionConfig(config);
00467     config->setGroup (grp);
00468 
00469     pd->setProgress(pd->progress()+1);
00470     KateApp::self()->processEvents();
00471   }
00472 
00473   delete pd;
00474 
00475   config->setGroup(prevGrp);
00476 }
00477 
00478 void KateDocManager::slotModifiedOnDisc (Kate::Document *doc, bool b, unsigned char reason)
00479 {
00480   if (m_docInfos[doc])
00481   {
00482     m_docInfos[doc]->modifiedOnDisc = b;
00483     m_docInfos[doc]->modifiedOnDiscReason = reason;
00484   }
00485 }
00486 
00487 void KateDocManager::slotModChanged(Kate::Document *doc)
00488 {
00489   saveMetaInfos(doc);
00490 }
00491 
00495 bool KateDocManager::loadMetaInfos(Kate::Document *doc, const KURL &url)
00496 {
00497   if (!m_saveMetaInfos)
00498     return false;
00499 
00500   if (!m_metaInfos->hasGroup(url.prettyURL()))
00501     return false;
00502 
00503   QCString md5;
00504   bool ok = true;
00505 
00506   if (computeUrlMD5(url, md5))
00507   {
00508     m_metaInfos->setGroup(url.prettyURL());
00509     QString old_md5 = m_metaInfos->readEntry("MD5");
00510 
00511     if ((const char *)md5 == old_md5)
00512       doc->readSessionConfig(m_metaInfos);
00513     else
00514     {
00515       m_metaInfos->deleteGroup(url.prettyURL());
00516       ok = false;
00517     }
00518 
00519     m_metaInfos->sync();
00520   }
00521 
00522   return ok && doc->url() == url;
00523 }
00524 
00528 void KateDocManager::saveMetaInfos(Kate::Document *doc)
00529 {
00530   QCString md5;
00531 
00532   if (!m_saveMetaInfos)
00533     return;
00534 
00535   if (doc->isModified())
00536   {
00537 //     kdDebug (13020) << "DOC MODIFIED: no meta data saved" << endl;
00538     return;
00539   }
00540 
00541   if (computeUrlMD5(doc->url(), md5))
00542   {
00543     m_metaInfos->setGroup(doc->url().prettyURL());
00544     doc->writeSessionConfig(m_metaInfos);
00545     m_metaInfos->writeEntry("MD5", (const char *)md5);
00546     m_metaInfos->writeEntry("Time", QDateTime::currentDateTime());
00547     m_metaInfos->sync();
00548   }
00549 }
00550 
00551 bool KateDocManager::computeUrlMD5(const KURL &url, QCString &result)
00552 {
00553   QFile f(url.path());
00554 
00555   if (f.open(IO_ReadOnly))
00556   {
00557     KMD5 md5;
00558 
00559     if (!md5.update(f))
00560       return false;
00561 
00562     md5.hexDigest(result);
00563     f.close();
00564   }
00565   else
00566     return false;
00567 
00568   return true;
00569 }
00570 
00571 // kate: space-indent on; indent-width 2; replace-tabs on;
KDE Home | KDE Accessibility Home | Description of Access Keys