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