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