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
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
00069 if (!m_docList.isEmpty())
00070 m_docList.at(0)->writeConfig(KateApp::self()->config());
00071
00072 if (m_saveMetaInfos)
00073 {
00074
00075 for (Kate::Document *doc = m_docList.first(); doc; doc = m_docList.next())
00076 saveMetaInfos(doc);
00077
00078
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
00139 if (activeId == id)
00140 {
00141
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
00229 return findDocumentByUrl (url) != 0;
00230 }
00231
00232 Kate::Document *KateDocManager::openURL (const KURL& url,const QString &encoding, uint *id)
00233 {
00234
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
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
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
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