00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
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 <kparts/factory.h>
00032
00033 #include <klocale.h>
00034 #include <kdebug.h>
00035 #include <kconfig.h>
00036 #include <kapplication.h>
00037 #include <klibloader.h>
00038 #include <kmdcodec.h>
00039
00040 #include <qdatetime.h>
00041 #include <qtextcodec.h>
00042 #include <qprogressdialog.h>
00043 #include <kmessagebox.h>
00044 #include <kencodingfiledialog.h>
00045 #include <ktexteditor/encodinginterface.h>
00046
00047
00048 KateDocManager::KateDocManager (QObject *parent)
00049 : QObject (parent)
00050 , m_saveMetaInfos(true)
00051 , m_daysMetaInfos(0)
00052 {
00053 m_factory = (KParts::Factory *) KLibLoader::self()->factory ("libkatepart");
00054
00055 m_documentManager = new Kate::DocumentManager (this);
00056 m_docList.setAutoDelete(true);
00057 m_docDict.setAutoDelete(false);
00058 m_docInfos.setAutoDelete(true);
00059
00060 m_dcop = new KateDocManagerDCOPIface (this);
00061
00062 m_metaInfos = new KConfig("metainfos", false, false, "appdata");
00063 Kate::Document::registerCommand(KateExternalToolsCommand::self());
00064
00065 createDoc ();
00066 }
00067
00068 KateDocManager::~KateDocManager ()
00069 {
00070 if (m_saveMetaInfos)
00071 {
00072
00073 for (Kate::Document *doc = m_docList.first(); doc; doc = m_docList.next())
00074 saveMetaInfos(doc);
00075
00076
00077 if (m_daysMetaInfos > 0)
00078 {
00079 QStringList groups = m_metaInfos->groupList();
00080 QDateTime *def = new QDateTime(QDate(1970, 1, 1));
00081 for (QStringList::Iterator it = groups.begin(); it != groups.end(); ++it)
00082 {
00083 m_metaInfos->setGroup(*it);
00084 QDateTime last = m_metaInfos->readDateTimeEntry("Time", def);
00085 if (last.daysTo(QDateTime::currentDateTime()) > m_daysMetaInfos)
00086 m_metaInfos->deleteGroup(*it);
00087 }
00088 delete def;
00089 }
00090 }
00091
00092 delete m_dcop;
00093 delete m_metaInfos;
00094 }
00095
00096 KateDocManager *KateDocManager::self ()
00097 {
00098 return KateApp::self()->kateDocumentManager ();
00099 }
00100
00101 Kate::Document *KateDocManager::createDoc ()
00102 {
00103 KTextEditor::Document *doc = (KTextEditor::Document *) m_factory->createPart (0, "", this, "", "KTextEditor::Document");
00104
00105 m_docList.append((Kate::Document *)doc);
00106 m_docDict.insert (doc->documentNumber(), (Kate::Document *)doc);
00107 m_docInfos.insert (doc, new KateDocumentInfo ());
00108
00109 if (m_docList.count() < 2)
00110 ((Kate::Document *)doc)->readConfig(kapp->config());
00111
00112 emit documentCreated ((Kate::Document *)doc);
00113 emit m_documentManager->documentCreated ((Kate::Document *)doc);
00114
00115 connect(doc,SIGNAL(modifiedOnDisc(Kate::Document *, bool, unsigned char)),this,SLOT(slotModifiedOnDisc(Kate::Document *, bool, unsigned char)));
00116 return (Kate::Document *)doc;
00117 }
00118
00119 void KateDocManager::deleteDoc (Kate::Document *doc)
00120 {
00121 uint id = doc->documentNumber();
00122 uint activeId = 0;
00123 if (m_currentDoc)
00124 activeId = m_currentDoc->documentNumber ();
00125
00126 if (m_docList.count() < 2)
00127 doc->writeConfig(kapp->config());
00128
00129 m_docInfos.remove (doc);
00130 m_docDict.remove (id);
00131 m_docList.remove (doc);
00132
00133 emit documentDeleted (id);
00134 emit m_documentManager->documentDeleted (id);
00135
00136
00137 if (activeId == id)
00138 {
00139
00140 m_currentDoc = 0;
00141
00142 emit documentChanged ();
00143 emit m_documentManager->documentChanged ();
00144 }
00145 }
00146
00147 Kate::Document *KateDocManager::document (uint n)
00148 {
00149 return m_docList.at(n);
00150 }
00151
00152 Kate::Document *KateDocManager::activeDocument ()
00153 {
00154 return m_currentDoc;
00155 }
00156
00157 void KateDocManager::setActiveDocument (Kate::Document *doc)
00158 {
00159 if (!doc)
00160 return;
00161
00162 if (m_currentDoc && (m_currentDoc->documentNumber() == doc->documentNumber()))
00163 return;
00164
00165 m_currentDoc = doc;
00166
00167 emit documentChanged ();
00168 emit m_documentManager->documentChanged ();
00169 }
00170
00171 Kate::Document *KateDocManager::firstDocument ()
00172 {
00173 return m_docList.first();
00174 }
00175
00176 Kate::Document *KateDocManager::nextDocument ()
00177 {
00178 return m_docList.next();
00179 }
00180
00181 Kate::Document *KateDocManager::documentWithID (uint id)
00182 {
00183 return m_docDict[id];
00184 }
00185
00186 const KateDocumentInfo *KateDocManager::documentInfo (Kate::Document *doc)
00187 {
00188 return m_docInfos[doc];
00189 }
00190
00191 int KateDocManager::findDocument (Kate::Document *doc)
00192 {
00193 return m_docList.find (doc);
00194 }
00195
00196 uint KateDocManager::documents ()
00197 {
00198 return m_docList.count ();
00199 }
00200
00201 int KateDocManager::findDocument ( KURL url )
00202 {
00203 QPtrListIterator<Kate::Document> it(m_docList);
00204
00205 for (; it.current(); ++it)
00206 {
00207 if ( it.current()->url() == url)
00208 return it.current()->documentNumber();
00209 }
00210 return -1;
00211 }
00212
00213 Kate::Document *KateDocManager::findDocumentByUrl( KURL url )
00214 {
00215 for (QPtrListIterator<Kate::Document> it(m_docList); it.current(); ++it)
00216 {
00217 if ( it.current()->url() == url)
00218 return it.current();
00219 }
00220
00221 return 0L;
00222 }
00223
00224 bool KateDocManager::isOpen(KURL url)
00225 {
00226
00227 return findDocumentByUrl (url) != 0;
00228 }
00229
00230 Kate::Document *KateDocManager::openURL (const KURL& url,const QString &encoding, uint *id)
00231 {
00232
00233 if (!documentList().isEmpty() && (documentList().count() == 1) && (!documentList().at(0)->isModified() && documentList().at(0)->url().isEmpty()))
00234 {
00235 Kate::Document* doc = documentList().getFirst();
00236
00237 doc->setEncoding(encoding);
00238
00239 if (!loadMetaInfos(doc, url))
00240 doc->openURL (url);
00241
00242 if (id)
00243 *id=doc->documentNumber();
00244
00245 connect(doc, SIGNAL(modStateChanged(Kate::Document *)), this, SLOT(slotModChanged(Kate::Document *)));
00246
00247 emit initialDocumentReplaced();
00248
00249 return doc;
00250 }
00251
00252 Kate::Document *doc = findDocumentByUrl (url);
00253 if ( !doc )
00254 {
00255 doc = (Kate::Document *)createDoc ();
00256
00257 doc->setEncoding(encoding.isNull() ? Kate::Document::defaultEncoding() : encoding);
00258
00259 if (!loadMetaInfos(doc, url))
00260 doc->openURL (url);
00261 }
00262
00263 if (id)
00264 *id=doc->documentNumber();
00265
00266 return doc;
00267 }
00268
00269 bool KateDocManager::closeDocument(class Kate::Document *doc,bool closeURL)
00270 {
00271 if (!doc) return false;
00272
00273 saveMetaInfos(doc);
00274 if (closeURL)
00275 if (!doc->closeURL()) return false;
00276
00277 QPtrList<Kate::View> closeList;
00278 uint documentNumber = doc->documentNumber();
00279
00280 for (uint i=0; i < ((KateApp *)kapp)->mainWindows (); i++ )
00281 {
00282 ((KateApp *)kapp)->kateMainWindow(i)->kateViewManager()->closeViews(documentNumber);
00283 }
00284
00285 deleteDoc (doc);
00286
00287
00288 if (m_docList.isEmpty())
00289 createDoc ();
00290
00291 return true;
00292 }
00293
00294 bool KateDocManager::closeDocument(uint n)
00295 {
00296 return closeDocument(document(n));
00297 }
00298
00299 bool KateDocManager::closeDocumentWithID(uint id)
00300 {
00301 return closeDocument(documentWithID(id));
00302 }
00303
00304 bool KateDocManager::closeAllDocuments(bool closeURL)
00305 {
00306 bool res = true;
00307
00308 QPtrList<Kate::Document> docs = m_docList;
00309
00310 for (uint i=0; i < ((KateApp *)kapp)->mainWindows (); i++ )
00311 {
00312 ((KateApp *)kapp)->kateMainWindow(i)->kateViewManager()->setViewActivationBlocked(true);
00313 }
00314
00315 while (!docs.isEmpty() && res)
00316 if (! closeDocument(docs.at(0),closeURL) )
00317 res = false;
00318 else
00319 docs.remove ((uint)0);
00320
00321 for (uint i=0; i < ((KateApp *)kapp)->mainWindows (); i++ )
00322 {
00323 ((KateApp *)kapp)->kateMainWindow(i)->kateViewManager()->setViewActivationBlocked(false);
00324
00325 for (uint s=0; s < ((KateApp *)kapp)->kateMainWindow(i)->kateViewManager()->containers()->count(); s++)
00326 ((KateApp *)kapp)->kateMainWindow(i)->kateViewManager()->containers()->at(s)->activateView (m_docList.at(0)->documentNumber());
00327 }
00328
00329 return res;
00330 }
00331
00332 QPtrList<Kate::Document> KateDocManager::modifiedDocumentList() {
00333 QPtrList<Kate::Document> modified;
00334 for (QPtrListIterator<Kate::Document> it(m_docList); it.current(); ++it) {
00335 Kate::Document *doc = it.current();
00336 if (doc->isModified()) {
00337 modified.append(doc);
00338 }
00339 }
00340 return modified;
00341 }
00342
00343
00344 bool KateDocManager::queryCloseDocuments(KateMainWindow *w)
00345 {
00346 uint docCount = m_docList.count();
00347 for (QPtrListIterator<Kate::Document> it(m_docList); it.current(); ++it)
00348 {
00349 Kate::Document *doc = it.current();
00350
00351 if (doc->url().isEmpty() && doc->isModified())
00352 {
00353 int msgres=KMessageBox::warningYesNoCancel( w,
00354 i18n("<p>The document '%1' has been modified, but not saved."
00355 "<p>Do you want to save your changes or discard them?").arg( doc->docName() ),
00356 i18n("Close Document"), KStdGuiItem::save(), KStdGuiItem::discard() );
00357
00358 if (msgres==KMessageBox::Cancel)
00359 return false;
00360
00361 if (msgres==KMessageBox::Yes)
00362 {
00363 KEncodingFileDialog::Result r=KEncodingFileDialog::getSaveURLAndEncoding(
00364 KTextEditor::encodingInterface(doc)->encoding(),QString::null,QString::null,w,i18n("Save As"));
00365
00366 doc->setEncoding( r.encoding );
00367
00368 if (!r.URLs.isEmpty())
00369 {
00370 KURL tmp = r.URLs.first();
00371
00372 if ( !doc->saveAs( tmp ) )
00373 return false;
00374 }
00375 else
00376 return false;
00377 }
00378 }
00379 else
00380 {
00381 if (!doc->queryClose())
00382 return false;
00383 }
00384 }
00385
00386
00387 if (m_docList.count() > docCount)
00388 {
00389 KMessageBox::information (w,
00390 i18n ("New file opened while trying to close Kate, closing aborted."),
00391 i18n ("Closing Aborted"));
00392 return false;
00393 }
00394
00395 return true;
00396 }
00397
00398
00399 void KateDocManager::saveAll()
00400 {
00401 for (QPtrListIterator<Kate::Document> it(m_docList); it.current(); ++it)
00402 if ( it.current()->isModified() && it.current()->views().count() )
00403 ((Kate::View*)it.current()->views().first())->save();
00404 }
00405
00406 void KateDocManager::saveDocumentList (KConfig* config)
00407 {
00408 QString prevGrp=config->group();
00409 config->setGroup ("Open Documents");
00410 QString grp = config->group();
00411
00412 config->writeEntry ("Count", m_docList.count());
00413
00414 int i=0;
00415 for ( Kate::Document *doc = m_docList.first(); doc; doc = m_docList.next() )
00416 {
00417 config->setGroup(QString("Document %1").arg(i));
00418 doc->writeSessionConfig(config);
00419 config->setGroup(grp);
00420
00421 i++;
00422 }
00423
00424 config->setGroup(prevGrp);
00425 }
00426
00427 void KateDocManager::restoreDocumentList (KConfig* config)
00428 {
00429 QString prevGrp=config->group();
00430 config->setGroup ("Open Documents");
00431 QString grp = config->group();
00432
00433 int count = config->readNumEntry("Count");
00434
00435 QProgressDialog *pd=new QProgressDialog(
00436 i18n("Reopening files from the last session..."),
00437 QString::null,
00438 count,
00439 0,
00440 "openprog");
00441
00442 bool first = true;
00443 for (int i=0; i < count; i++)
00444 {
00445 config->setGroup(QString("Document %1").arg(i));
00446 Kate::Document *doc = 0;
00447
00448 if (first)
00449 {
00450 first = false;
00451 doc = document (0);
00452 }
00453 else
00454 doc = createDoc ();
00455
00456 doc->readSessionConfig(config);
00457 config->setGroup (grp);
00458
00459 pd->setProgress(pd->progress()+1);
00460 kapp->processEvents();
00461 }
00462
00463 delete pd;
00464
00465 config->setGroup(prevGrp);
00466 }
00467
00468 void KateDocManager::slotModifiedOnDisc (Kate::Document *doc, bool b, unsigned char reason)
00469 {
00470 if (m_docInfos[doc])
00471 {
00472 m_docInfos[doc]->modifiedOnDisc = b;
00473 m_docInfos[doc]->modifiedOnDiscReason = reason;
00474 }
00475 }
00476
00477 void KateDocManager::slotModChanged(Kate::Document *doc)
00478 {
00479 saveMetaInfos(doc);
00480 }
00481
00485 bool KateDocManager::loadMetaInfos(Kate::Document *doc, const KURL &url)
00486 {
00487 if (!m_saveMetaInfos)
00488 return false;
00489
00490 if (!m_metaInfos->hasGroup(url.prettyURL()))
00491 return false;
00492
00493 QCString md5;
00494 bool ok = true;
00495
00496 if (computeUrlMD5(url, md5))
00497 {
00498 m_metaInfos->setGroup(url.prettyURL());
00499 QString old_md5 = m_metaInfos->readEntry("MD5");
00500
00501 if ((const char *)md5 == old_md5)
00502 doc->readSessionConfig(m_metaInfos);
00503 else
00504 {
00505 m_metaInfos->deleteGroup(url.prettyURL());
00506 ok = false;
00507 }
00508
00509 m_metaInfos->sync();
00510 }
00511
00512 return ok && doc->url() == url;
00513 }
00514
00518 void KateDocManager::saveMetaInfos(Kate::Document *doc)
00519 {
00520 QCString md5;
00521
00522 if (!m_saveMetaInfos)
00523 return;
00524
00525 if (doc->isModified())
00526 {
00527
00528 return;
00529 }
00530
00531 if (computeUrlMD5(doc->url(), md5))
00532 {
00533 m_metaInfos->setGroup(doc->url().prettyURL());
00534 doc->writeSessionConfig(m_metaInfos);
00535 m_metaInfos->writeEntry("MD5", (const char *)md5);
00536 m_metaInfos->writeEntry("Time", QDateTime::currentDateTime());
00537 m_metaInfos->sync();
00538 }
00539 }
00540
00541 bool KateDocManager::computeUrlMD5(const KURL &url, QCString &result)
00542 {
00543 QFile f(url.path());
00544
00545 if (f.open(IO_ReadOnly))
00546 {
00547 KMD5 md5;
00548
00549 if (!md5.update(f))
00550 return false;
00551
00552 md5.hexDigest(result);
00553 f.close();
00554 }
00555 else
00556 return false;
00557
00558 return true;
00559 }
00560