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