Merge lp:~elgaton/ubuntu/precise/kile/fix-for-994498 into lp:ubuntu/precise/kile

Proposed by Alessandro Menti
Status: Work in progress
Proposed branch: lp:~elgaton/ubuntu/precise/kile/fix-for-994498
Merge into: lp:ubuntu/precise/kile
Diff against target: 2490 lines (+2429/-5)
8 files modified
.pc/.quilt_patches (+1/-0)
.pc/.quilt_series (+1/-0)
.pc/applied-patches (+1/-0)
.pc/kile-fix-closing-994498.patch/src/kiledocmanager.cpp (+2382/-0)
debian/changelog (+7/-0)
debian/patches/kile-fix-closing-994498.patch (+31/-0)
debian/patches/series (+1/-0)
src/kiledocmanager.cpp (+5/-5)
To merge this branch: bzr merge lp:~elgaton/ubuntu/precise/kile/fix-for-994498
Reviewer Review Type Date Requested Status
Marc Deslauriers Approve
Ubuntu branches Pending
Review via email: mp+118919@code.launchpad.net

Description of the change

Backported patch from upstream to prevent crashes when Kile is closed and a project file is open

To post a comment you must log in.
49. By Alessandro Menti

* Added missing .pc files

Revision history for this message
Marc Deslauriers (mdeslaur) wrote :

I've uploaded a slightly modified version of this merge request to precise-proposed for processing by the SRU team. Thanks!

review: Approve

Unmerged revisions

49. By Alessandro Menti

* Added missing .pc files

48. By Alessandro Menti <email address hidden>

* Fixed wrong distribution in the changelog

47. By Alessandro Menti <email address hidden>

* Added missing patch

46. By Alessandro Menti <email address hidden>

Fixed segfault on close when a project is open (LP: #994498). Patch by
Eugene Shalygin.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== added file '.pc/.quilt_patches'
2--- .pc/.quilt_patches 1970-01-01 00:00:00 +0000
3+++ .pc/.quilt_patches 2012-08-25 08:51:18 +0000
4@@ -0,0 +1,1 @@
5+debian/patches
6
7=== added file '.pc/.quilt_series'
8--- .pc/.quilt_series 1970-01-01 00:00:00 +0000
9+++ .pc/.quilt_series 2012-08-25 08:51:18 +0000
10@@ -0,0 +1,1 @@
11+series
12
13=== modified file '.pc/applied-patches'
14--- .pc/applied-patches 2012-04-16 00:46:18 +0000
15+++ .pc/applied-patches 2012-08-25 08:51:18 +0000
16@@ -3,3 +3,4 @@
17 kubuntu_01_improved_viewpart_warning.diff
18 kubuntu_02_disable_embedded_kbibtex.diff
19 kubuntu_use_utf8.diff
20+kile-fix-closing-994498.patch
21
22=== added directory '.pc/kile-fix-closing-994498.patch'
23=== added directory '.pc/kile-fix-closing-994498.patch/src'
24=== added file '.pc/kile-fix-closing-994498.patch/src/kiledocmanager.cpp'
25--- .pc/kile-fix-closing-994498.patch/src/kiledocmanager.cpp 1970-01-01 00:00:00 +0000
26+++ .pc/kile-fix-closing-994498.patch/src/kiledocmanager.cpp 2012-08-25 08:51:18 +0000
27@@ -0,0 +1,2382 @@
28+/*****************************************************************************
29+* Copyright (C) 2004 by Jeroen Wijnhout (Jeroen.Wijnhout@kdemail.net) *
30+* (C) 2006-2010 by Michel Ludwig (michel.ludwig@kdemail.net) *
31+* (C) 2007 by Holger Danielsson (holger.danielsson@versanet.de) *
32+******************************************************************************/
33+
34+/***************************************************************************
35+ * *
36+ * This program is free software; you can redistribute it and/or modify *
37+ * it under the terms of the GNU General Public License as published by *
38+ * the Free Software Foundation; either version 2 of the License, or *
39+ * (at your option) any later version. *
40+ * *
41+ ***************************************************************************/
42+
43+// 2007-03-12 dani
44+// - use KileDocument::Extensions
45+
46+#include "kiledocmanager.h"
47+
48+#include <QAbstractItemView>
49+
50+#include <QTextCodec>
51+#include <QFile>
52+#include <QDir>
53+
54+#include <QList>
55+#include <QDropEvent>
56+
57+#include <KTextEditor/Document>
58+#include <KTextEditor/Editor>
59+#include <KTextEditor/EditorChooser>
60+#include <KTextEditor/SessionConfigInterface>
61+#include <KTextEditor/View>
62+#include <kapplication.h>
63+#include "kiledebug.h"
64+#include <KEncodingFileDialog>
65+#include <KLocale>
66+#include <KMimeType>
67+#include <kmessagebox.h>
68+#include <KProgressDialog>
69+#include <kfile.h>
70+#include <krun.h>
71+#include <kstandarddirs.h>
72+#include <kio/netaccess.h>
73+#include <kpushbutton.h>
74+#include <kurl.h>
75+#include <kfileitem.h>
76+
77+#include "templates.h"
78+#include "dialogs/newfilewizard.h"
79+#include "dialogs/managetemplatesdialog.h"
80+#include "kileinfo.h"
81+#include "scriptmanager.h"
82+#include "kileproject.h"
83+#include "documentinfo.h"
84+#include "kileviewmanager.h"
85+#include "widgets/filebrowserwidget.h"
86+#include "widgets/projectview.h"
87+#include "widgets/structurewidget.h"
88+#include "dialogs/projectdialogs.h"
89+#include "kiletool.h"
90+#include "kiletool_enums.h"
91+#include "kilestdtools.h"
92+#include "kilelistselector.h"
93+#include "kiletoolmanager.h"
94+#include "widgets/konsolewidget.h"
95+#include "kileconfig.h"
96+#include "widgets/logwidget.h"
97+#include "widgets/progressdialog.h"
98+#include "dialogs/cleandialog.h"
99+
100+/*
101+ * Newly created text documents have an empty URL and a non-empty document name.
102+ */
103+
104+/*
105+ * WARNING: Several methods in the document manager can open dialogs and consequently
106+ * launch a new event loop. It is therefore possible that the auto save feature
107+ * gets triggered when such a dialog is shown, potentially modifying variables
108+ * that are currently being modified by the method in question. It is therefore
109+ * *essential* that the 'm_autoSaveLock' variable is locked before such a method is
110+ * executed (also see the 'Locker' class).
111+ */
112+
113+class Locker
114+{
115+ public:
116+ Locker(unsigned int *lock)
117+ {
118+ m_lock = lock;
119+ ++*m_lock;
120+ }
121+
122+ ~Locker()
123+ {
124+ if(*m_lock == 0) {
125+ return;
126+ }
127+ --*m_lock;
128+ }
129+
130+ private:
131+ unsigned int *m_lock;
132+};
133+
134+#define MAX_NUMBER_OF_STORED_SETTINGS 50
135+
136+namespace KileDocument
137+{
138+
139+Manager::Manager(KileInfo *info, QObject *parent, const char *name) :
140+ QObject(parent),
141+ m_ki(info),
142+ m_progressDialog(NULL),
143+ m_autoSaveLock(0),
144+ m_currentlySavingAll(false)
145+{
146+ setObjectName(name);
147+ m_editor = KTextEditor::EditorChooser::editor();
148+ if(!m_editor) {
149+ KMessageBox::error(m_ki->mainWindow(), i18n("No editor component found. Please check your KDE installation."),
150+ i18n("No editor component found."));
151+ }
152+}
153+
154+Manager::~Manager()
155+{
156+ KILE_DEBUG() << "==KileDocument::Manager::~Manager()=========";
157+ if(m_progressDialog.isNull()) {
158+ delete m_progressDialog.data();
159+ }
160+}
161+
162+void Manager::trashDoc(TextInfo *docinfo, KTextEditor::Document *doc /*= NULL */ )
163+{
164+ KILE_DEBUG() << "==void Manager::trashDoc(" << docinfo->url().toLocalFile() << ")=====";
165+
166+ if(m_ki->isOpen(docinfo->url())) {
167+ return;
168+ }
169+
170+ if(doc) {
171+ doc = docinfo->getDoc();
172+ }
173+
174+ //look for doc before we detach the docinfo
175+ //if we do it the other way around, docFor will always return nil
176+ if(!doc) {
177+ doc = docFor(docinfo->url());
178+ }
179+
180+ KILE_DEBUG() << "DETACHING " << docinfo;
181+ docinfo->detach();
182+
183+ KILE_DEBUG() << "\tTRASHING " << doc;
184+ if(!doc) {
185+ return;
186+ }
187+
188+ KILE_DEBUG() << "just checking: docinfo->getDoc() = " << docinfo->getDoc();
189+ KILE_DEBUG() << "just checking: docFor(docinfo->url()) = " << docFor(docinfo->url());
190+
191+ for (int i = 0; i < m_textInfoList.count(); ++i) {
192+ if((m_textInfoList.at(i) != docinfo) && (m_textInfoList.at(i)->getDoc() == doc)) {
193+ KMessageBox::information(0, i18n("The internal structure of Kile is corrupted (probably due to a bug in Kile). Please select Save All from the File menu and close Kile.\nThe Kile team apologizes for any inconvenience and would appreciate a bug report."));
194+ kWarning() << "docinfo " << m_textInfoList.at(i) << " url " << m_textInfoList.at(i)->url().fileName() << " has a wild pointer!!!";
195+ }
196+ }
197+
198+ KILE_DEBUG() << "DELETING doc";
199+ delete doc;
200+}
201+
202+// update all Info's with changed user commands
203+void Manager::updateInfos()
204+{
205+ for(QList<TextInfo*>::iterator it = m_textInfoList.begin(); it != m_textInfoList.end(); ++it) {
206+ (*it)->updateStructLevelInfo();
207+ }
208+}
209+
210+bool Manager::isAutoSaveAllowed()
211+{
212+ return (m_autoSaveLock == 0);
213+}
214+
215+KTextEditor::Editor* Manager::getEditor()
216+{
217+ return m_editor;
218+}
219+
220+KTextEditor::Document* Manager::docFor(const KUrl & url)
221+{
222+ for(QList<TextInfo*>::iterator it = m_textInfoList.begin(); it != m_textInfoList.end(); ++it) {
223+ TextInfo *info = *it;
224+
225+ if(m_ki->similarOrEqualURL(info->url(), url)) {
226+ return info->getDoc();
227+ }
228+ }
229+
230+ return NULL;
231+}
232+
233+Info* Manager::getInfo() const
234+{
235+ KTextEditor::Document *doc = m_ki->activeTextDocument();
236+ if ( doc != 0L )
237+ return textInfoFor(doc);
238+ else
239+ return 0L;
240+}
241+
242+TextInfo* Manager::textInfoFor(const QString & path) const
243+{
244+ if(path.isEmpty()) {
245+ return NULL;
246+ }
247+
248+ KILE_DEBUG() << "==KileInfo::textInfoFor(" << path << ")==========================";
249+ for(QList<TextInfo*>::const_iterator it = m_textInfoList.begin(); it != m_textInfoList.end(); ++it) {
250+ TextInfo *info = *it;
251+
252+ if(info->url().toLocalFile() == path) {
253+ return info;
254+ }
255+ }
256+
257+ KILE_DEBUG() << "\tCOULD NOT find info for " << path;
258+ return NULL;
259+}
260+
261+TextInfo* Manager::textInfoForURL(const KUrl& url)
262+{
263+ if(url.isEmpty()) {
264+ return NULL;
265+ }
266+
267+ KILE_DEBUG() << "==KileInfo::textInfoFor(" << url << ")==========================";
268+
269+ for(QList<TextInfo*>::iterator it = m_textInfoList.begin(); it != m_textInfoList.end(); ++it) {
270+ TextInfo *info = *it;
271+
272+ if (info->url() == url) {
273+ return info;
274+ }
275+ }
276+
277+ KILE_DEBUG() << "\tCOULD NOT find info for " << url;
278+ return NULL;
279+}
280+
281+TextInfo* Manager::textInfoFor(KTextEditor::Document* doc) const
282+{
283+ if(!doc) {
284+ return NULL;
285+ }
286+
287+ for(QList<TextInfo*>::const_iterator it = m_textInfoList.begin(); it != m_textInfoList.end(); ++it) {
288+ if((*it)->getDoc() == doc) {
289+ return (*it);
290+ }
291+ }
292+
293+ return NULL;
294+}
295+
296+void Manager::mapItem(TextInfo *docinfo, KileProjectItem *item)
297+{
298+ item->setInfo(docinfo);
299+}
300+
301+KileProject* Manager::projectFor(const KUrl &projecturl)
302+{
303+ //find project with url = projecturl
304+ for(QList<KileProject*>::iterator it = m_projects.begin(); it != m_projects.end(); ++it) {
305+ KileProject *project = *it;
306+ if(project->url() == projecturl) {
307+ return project;
308+ }
309+ }
310+
311+ return NULL;
312+}
313+
314+KileProject* Manager::projectFor(const QString &name)
315+{
316+ //find project with url = projecturl
317+ for(QList<KileProject*>::iterator it = m_projects.begin(); it != m_projects.end(); ++it) {
318+ KileProject *project = *it;
319+
320+ if (project->name() == name) {
321+ return project;
322+ }
323+ }
324+
325+ return NULL;
326+}
327+
328+KileProjectItem* Manager::itemFor(const KUrl &url, KileProject *project /*=0L*/) const
329+{
330+ if (!project) {
331+ for(QList<KileProject*>::const_iterator it = m_projects.begin(); it != m_projects.end(); ++it) {
332+ KileProject *project = *it;
333+
334+ KILE_DEBUG() << "looking in project " << project->name();
335+ if (project->contains(url)) {
336+ KILE_DEBUG() << "\t\tfound!";
337+ return project->item(url);
338+ }
339+ }
340+ KILE_DEBUG() << "\t nothing found";
341+ }
342+ else {
343+ if(project->contains(url)) {
344+ return project->item(url);
345+ }
346+ }
347+
348+ return NULL;
349+}
350+
351+KileProjectItem* Manager::itemFor(Info *docinfo, KileProject *project /*=0*/) const
352+{
353+ if(docinfo)
354+ return itemFor(docinfo->url(), project);
355+ else
356+ return NULL;
357+}
358+
359+QList<KileProjectItem*> Manager::itemsFor(Info *docinfo) const
360+{
361+ if(!docinfo) {
362+ return QList<KileProjectItem*>();
363+ }
364+
365+ KILE_DEBUG() << "==KileInfo::itemsFor(" << docinfo->url().fileName() << ")============";
366+ QList<KileProjectItem*> list;
367+ for(QList<KileProject*>::const_iterator it = m_projects.begin(); it != m_projects.end(); ++it) {
368+ KileProject *project = *it;
369+
370+ KILE_DEBUG() << "\tproject: " << (*it)->name();
371+ if(project->contains(docinfo)) {
372+ KILE_DEBUG() << "\t\tcontains";
373+ list.append(project->item(docinfo));
374+ }
375+ }
376+
377+ return list;
378+}
379+
380+QList<KileProjectItem*> Manager::itemsFor(const KUrl& url) const
381+{
382+ QList<KileProjectItem*> list;
383+ for(QList<KileProject*>::const_iterator it = m_projects.begin(); it != m_projects.end(); ++it) {
384+ KileProject *project = *it;
385+
386+ if(project->contains(url)) {
387+ list.append(project->item(url));
388+ }
389+ }
390+
391+ return list;
392+}
393+
394+bool Manager::isProjectOpen()
395+{
396+ return ( m_projects.count() > 0 );
397+}
398+
399+KileProject* Manager::activeProject()
400+{
401+ KTextEditor::Document *doc = m_ki->activeTextDocument();
402+
403+ if (doc) {
404+ for(QList<KileProject*>::iterator it = m_projects.begin(); it != m_projects.end(); ++it) {
405+ KileProject *project = *it;
406+
407+ if(project->contains(doc->url())) {
408+ return project;
409+ }
410+ }
411+ }
412+
413+ return NULL;
414+}
415+
416+KileProjectItem* Manager::activeProjectItem()
417+{
418+ KileProject *curpr = activeProject();
419+ KTextEditor::Document *doc = m_ki->activeTextDocument();
420+
421+ if (curpr && doc) {
422+ QList<KileProjectItem*> list = curpr->items();
423+
424+ for(QList<KileProjectItem*>::iterator it = list.begin(); it != list.end(); ++it) {
425+ KileProjectItem *item = *it;
426+
427+ if (item->url() == doc->url()) {
428+ return item;
429+ }
430+ }
431+ }
432+
433+ return NULL;
434+}
435+
436+TextInfo* Manager::createTextDocumentInfo(KileDocument::Type type, const KUrl & url, const KUrl& baseDirectory)
437+{
438+ TextInfo *docinfo = 0L;
439+
440+ //see if this file belongs to an opened project
441+ KileProjectItem *item = itemFor(url);
442+ if ( item != 0L ) docinfo = item->getInfo();
443+
444+ if ( docinfo == 0L )
445+ {
446+ switch(type)
447+ {
448+ case Undefined: // fall through
449+ case Text:
450+ KILE_DEBUG() << "CREATING TextInfo for " << url.url();
451+ docinfo = new TextInfo(NULL, m_ki->extensions(),
452+ m_ki->abbreviationManager());
453+ break;
454+ case LaTeX:
455+ KILE_DEBUG() << "CREATING LaTeXInfo for " << url.url();
456+ docinfo = new LaTeXInfo(NULL, m_ki->extensions(),
457+ m_ki->abbreviationManager(),
458+ m_ki->latexCommands(),
459+ m_ki->editorExtension(),
460+ m_ki->configurationManager(),
461+ m_ki->codeCompletionManager());
462+ break;
463+ case BibTeX:
464+ KILE_DEBUG() << "CREATING BibInfo for " << url.url();
465+ docinfo = new BibInfo(NULL, m_ki->extensions(),
466+ m_ki->abbreviationManager(),
467+ m_ki->latexCommands());
468+ break;
469+ case Script:
470+ KILE_DEBUG() << "CREATING ScriptInfo for " << url.url();
471+ docinfo = new ScriptInfo(NULL, m_ki->extensions(),
472+ m_ki->abbreviationManager());
473+ break;
474+ }
475+ docinfo->setBaseDirectory(baseDirectory);
476+ emit(documentInfoCreated(docinfo));
477+ m_textInfoList.append(docinfo);
478+ }
479+
480+ KILE_DEBUG() << "DOCINFO: returning " << docinfo << " " << docinfo->url().fileName();
481+ return docinfo;
482+}
483+
484+void Manager::recreateTextDocumentInfo(TextInfo *oldinfo)
485+{
486+ QList<KileProjectItem*> list = itemsFor(oldinfo);
487+ KUrl url = oldinfo->url();
488+ TextInfo *newinfo = createTextDocumentInfo(m_ki->extensions()->determineDocumentType(url), url, oldinfo->getBaseDirectory());
489+
490+ newinfo->setDoc(oldinfo->getDoc());
491+
492+ for(QList<KileProjectItem*>::iterator it = list.begin(); it != list.end(); ++it) {
493+ (*it)->setInfo(newinfo);
494+ }
495+
496+ removeTextDocumentInfo(oldinfo);
497+
498+ emit(updateStructure(false, newinfo));
499+}
500+
501+bool Manager::removeTextDocumentInfo(TextInfo *docinfo, bool closingproject /* = false */)
502+{
503+ KILE_DEBUG() << "==Manager::removeTextDocumentInfo(Info *docinfo)=====";
504+ QList<KileProjectItem*> itms = itemsFor(docinfo);
505+ bool oneItem = false;
506+ if(itms.count() == 1) {
507+ oneItem = true;
508+ }
509+
510+ if(itms.count() == 0 || ( closingproject && oneItem )) {
511+ KILE_DEBUG() << "\tremoving " << docinfo << " count = " << m_textInfoList.count();
512+ m_textInfoList.removeAll(docinfo);
513+
514+ emit(closingDocument(docinfo));
515+
516+ cleanupDocumentInfoForProjectItems(docinfo);
517+ delete docinfo;
518+
519+ return true;
520+ }
521+
522+ KILE_DEBUG() << "\tnot removing " << docinfo;
523+ return false;
524+}
525+
526+
527+KTextEditor::Document* Manager::createDocument(const KUrl& url, TextInfo *docinfo, const QString& encoding,
528+ const QString& mode,
529+ const QString& highlight)
530+{
531+ KILE_DEBUG() << "==KTextEditor::Document* Manager::createDocument()===========";
532+
533+ KTextEditor::Document *doc = NULL;
534+
535+ if(!m_editor) {
536+ return NULL;
537+ }
538+
539+ doc = docFor(url);
540+ if (doc) {
541+ kWarning() << url << " already has a document!";
542+ return doc;
543+ }
544+ doc = m_editor->createDocument(NULL);
545+ KILE_DEBUG() << "appending document " << doc;
546+
547+ docinfo->setDoc(doc); // do this here to set up all the signals correctly in 'TextInfo'
548+ doc->setEncoding(encoding);
549+
550+ KILE_DEBUG() << "url is = " << docinfo->url();
551+
552+ if(!url.isEmpty()) {
553+ bool r = doc->openUrl(url);
554+ // don't add scripts to the recent files
555+ if(r && docinfo->getType() != Script) {
556+ emit(addToRecentFiles(url));
557+ }
558+ }
559+
560+ //handle changes of the document
561+ connect(doc, SIGNAL(documentNameChanged(KTextEditor::Document*)), this, SIGNAL(documentNameChanged(KTextEditor::Document*)));
562+ connect(doc, SIGNAL(documentUrlChanged(KTextEditor::Document*)), this, SIGNAL(documentUrlChanged(KTextEditor::Document*)));
563+ connect(doc, SIGNAL(modifiedChanged(KTextEditor::Document*)), this, SLOT(newDocumentStatus(KTextEditor::Document*)));
564+ KTextEditor::ModificationInterface *modificationInterface = qobject_cast<KTextEditor::ModificationInterface*>(doc);
565+ if(modificationInterface) {
566+ modificationInterface->setModifiedOnDiskWarning(true);
567+ connect(doc, SIGNAL(modifiedOnDisk(KTextEditor::Document*,bool,KTextEditor::ModificationInterface::ModifiedOnDiskReason)),
568+ this, SIGNAL(documentModificationStatusChanged(KTextEditor::Document*,bool,KTextEditor::ModificationInterface::ModifiedOnDiskReason)));
569+ }
570+
571+ if(!mode.isEmpty()){
572+ docinfo->setMode(mode); // this ensures that mode passed with the mode parameter is actually used
573+ }
574+ if(!highlight.isEmpty()){
575+ docinfo->setHighlightingMode(highlight);
576+ }
577+ // FIXME: the whole structure updating stuff needs to be rewritten; updates should originate from
578+ // the docinfo only, i.e. the structure view should just react to changes!
579+ connect(docinfo, SIGNAL(completed(KileDocument::Info*)), m_ki->structureWidget(), SLOT(update(KileDocument::Info*)));
580+
581+ KILE_DEBUG() << "createDocument: url " << doc->url();
582+ KILE_DEBUG() << "createDocument: SANITY check: " << (docinfo->getDoc() == docFor(docinfo->url()));
583+ return doc;
584+}
585+
586+KTextEditor::View* Manager::loadItem(KileDocument::Type type, KileProjectItem *item, const QString & text, bool openProjectItemViews)
587+{
588+ KTextEditor::View *view = NULL;
589+
590+ KILE_DEBUG() << "==loadItem(" << item->url().toLocalFile() << ")======";
591+
592+ if(item->type() != KileProjectItem::Image) {
593+ view = loadText(type, item->url(), item->encoding(), openProjectItemViews && item->isOpen(), item->mode(), item->highlight(), text);
594+ KILE_DEBUG() << "\tloadItem: docfor = " << docFor(item->url().toLocalFile());
595+
596+ TextInfo *docinfo = textInfoFor(item->url().toLocalFile());
597+ item->setInfo(docinfo);
598+
599+ KILE_DEBUG() << "\tloadItem: docinfo = " << docinfo << " doc = " << docinfo->getDoc() << " docfor = " << docFor(docinfo->url().toLocalFile());
600+ if ( docinfo->getDoc() != docFor(docinfo->url().toLocalFile()) ) kWarning() << "docinfo->getDoc() != docFor()";
601+ }
602+ else {
603+ KILE_DEBUG() << "\tloadItem: no document generated";
604+ TextInfo *docinfo = createTextDocumentInfo(m_ki->extensions()->determineDocumentType(item->url()), item->url());
605+ item->setInfo(docinfo);
606+
607+ if(!docFor(item->url())) {
608+ docinfo->detach();
609+ KILE_DEBUG() << "\t\t\tdetached";
610+ }
611+ }
612+
613+ return view;
614+}
615+
616+KTextEditor::View* Manager::loadText(KileDocument::Type type, const KUrl& url, const QString& encoding,
617+ bool create,
618+ const QString& mode,
619+ const QString& highlight,
620+ const QString& text,
621+ int index,
622+ const KUrl& baseDirectory)
623+{
624+ KILE_DEBUG() << "==loadText(" << url.url() << ")=================";
625+ //if doc already opened, update the structure view and return the view
626+ if(!url.isEmpty() && m_ki->isOpen(url)) {
627+ return m_ki->viewManager()->switchToTextView(url);
628+ }
629+
630+ TextInfo *docinfo = createTextDocumentInfo(type, url, baseDirectory);
631+ KTextEditor::Document *doc = createDocument(url, docinfo, encoding, mode, highlight);
632+
633+ m_ki->structureWidget()->clean(docinfo);
634+
635+ if(!text.isEmpty()) {
636+ doc->setText(text);
637+ }
638+
639+ //FIXME: use signal/slot
640+ if (doc && create) {
641+ return m_ki->viewManager()->createTextView(docinfo, index);
642+ }
643+
644+ KILE_DEBUG() << "just after createView()";
645+ KILE_DEBUG() << "\tdocinfo = " << docinfo << " doc = " << docinfo->getDoc() << " docfor = " << docFor(docinfo->url().toLocalFile());
646+
647+ return NULL;
648+}
649+
650+//FIXME: template stuff should be in own class
651+KTextEditor::View* Manager::loadTemplate(TemplateItem *sel)
652+{
653+ KILE_DEBUG() << "templateitem *sel = " << sel;
654+ QString text;
655+
656+ if(!sel) {
657+ return NULL;
658+ }
659+
660+ Locker lock(&m_autoSaveLock);
661+ if (sel->name() != KileTemplate::Manager::defaultEmptyTemplateCaption()
662+ && sel->name() != KileTemplate::Manager::defaultEmptyLaTeXTemplateCaption()
663+ && sel->name() != KileTemplate::Manager::defaultEmptyBibTeXTemplateCaption()) {
664+ if(!m_editor) {
665+ return NULL;
666+ }
667+ //create a new document to open the template in
668+ KTextEditor::Document *tempdoc = m_editor->createDocument(NULL);
669+
670+ if (!tempdoc->openUrl(KUrl(sel->path()))) {
671+ KMessageBox::error(m_ki->mainWindow(), i18n("Could not find template: %1", sel->name()), i18n("File Not Found"));
672+ }
673+ else {
674+ //substitute templates variables
675+ text = tempdoc->text();
676+ delete tempdoc;
677+ replaceTemplateVariables(text);
678+ }
679+ }
680+
681+ KileDocument::Type type = sel->type();
682+ //always set the base directory for scripts
683+ return createDocumentWithText(text, type, QString(), (type == KileDocument::Script ? m_ki->scriptManager()->getLocalScriptDirectory() : QString()));
684+}
685+
686+KTextEditor::View* Manager::createDocumentWithText(const QString& text, KileDocument::Type type /* = KileDocument::Undefined */, const QString& /* extension */, const KUrl& baseDirectory)
687+{
688+ KTextEditor::View *view = loadText(type, KUrl(), QString(), true, QString(), QString(), text, -1, baseDirectory);
689+ if(view) {
690+ //FIXME this shouldn't be necessary!!!
691+ view->document()->setModified(true);
692+ newDocumentStatus(view->document());
693+ }
694+
695+ return view;
696+}
697+
698+KTextEditor::View* Manager::createNewJScript()
699+{
700+ KTextEditor::View *view = createDocumentWithText(QString(), Script, "js", m_ki->scriptManager()->getLocalScriptDirectory());
701+ emit(updateStructure(false, NULL));
702+ emit(updateModeStatus());
703+ return view;
704+}
705+
706+KTextEditor::View* Manager::createNewLaTeXDocument()
707+{
708+ KTextEditor::View *view = createDocumentWithText(QString(), LaTeX);
709+ emit(updateStructure(false, NULL));
710+ emit(updateModeStatus());
711+ return view;
712+}
713+
714+void Manager::replaceTemplateVariables(QString &line)
715+{
716+ line=line.replace("$$AUTHOR$$", KileConfig::author());
717+ line=line.replace("$$DOCUMENTCLASSOPTIONS$$", KileConfig::documentClassOptions());
718+ if (!KileConfig::templateEncoding().isEmpty()) { line=line.replace("$$INPUTENCODING$$", "\\usepackage["+ KileConfig::templateEncoding() +"]{inputenc}");}
719+ else {
720+ line = line.remove("$$INPUTENCODING$$");
721+ }
722+}
723+
724+void Manager::createTemplate()
725+{
726+ KTextEditor::View *view = m_ki->viewManager()->currentTextView();
727+ if (view) {
728+ if (view->document()->isModified()) {
729+ KMessageBox::information(m_ki->mainWindow(),i18n("Please save the file first."));
730+ return;
731+ }
732+ }
733+ else {
734+ KMessageBox::information(m_ki->mainWindow(),i18n("Open/create a document first."));
735+ return;
736+ }
737+
738+ KUrl url = view->document()->url();
739+ KileDocument::Type type = m_ki->extensions()->determineDocumentType(url);
740+
741+ if(type == KileDocument::Undefined || type == KileDocument::Text) {
742+ KMessageBox::information(m_ki->mainWindow(),i18n("A template for this type of document cannot be created."));
743+ return;
744+ }
745+
746+ ManageTemplatesDialog mtd(m_ki->templateManager(), url, i18n("Create Template From Document"));
747+ mtd.exec();
748+}
749+
750+void Manager::removeTemplate()
751+{
752+ ManageTemplatesDialog mtd(m_ki->templateManager(), i18n("Remove Template"));
753+ mtd.exec();
754+}
755+
756+void Manager::fileNew(KileDocument::Type type)
757+{
758+ NewFileWizard *nfw = new NewFileWizard(m_ki->templateManager(), type, m_ki->mainWindow());
759+ if(nfw->exec()) {
760+ Locker lock(&m_autoSaveLock);
761+ KTextEditor::View *view = loadTemplate(nfw->getSelection());
762+ if(view) {
763+ if(nfw->useWizard()) {
764+ emit(startWizard());
765+ }
766+ emit(updateStructure(false, NULL));
767+ emit(updateModeStatus());
768+ }
769+ }
770+ delete nfw;
771+}
772+
773+void Manager::fileNewScript()
774+{
775+ Locker lock(&m_autoSaveLock);
776+ fileNew(KileDocument::Script);
777+}
778+
779+void Manager::fileNew(const KUrl& url)
780+{
781+ Locker lock(&m_autoSaveLock);
782+ //create an empty file
783+ QFile file(url.toLocalFile());
784+ file.open(QIODevice::ReadWrite);
785+ file.close();
786+
787+ fileOpen(url, QString());
788+}
789+
790+void Manager::fileOpen()
791+{
792+ //determine the starting dir for the file dialog
793+ QString compileName = m_ki->getCompileName();
794+ QString currentDir;
795+ if(QFileInfo(compileName).exists()) {
796+ currentDir = QFileInfo(compileName).absolutePath();
797+ }
798+ else {
799+ currentDir = m_ki->fileSelector()->currentUrl().toLocalFile();
800+ }
801+
802+ // use a filter for fileOpen dialog
803+ Extensions *extensions = m_ki->extensions();
804+ QString filter = extensions->latexDocumentFileFilter() + '\n'
805+ + extensions->latexPackageFileFilter() + '\n'
806+ + extensions->bibtexFileFilter() + '\n'
807+ + extensions->metapostFileFilter() + '\n'
808+ + "*|" + i18n("All Files");
809+
810+ // try to get the current encoding, this is kind of ugly ...
811+ QString encoding = m_ki->toolManager()->config()->group("Kate Document Defaults").readEntry("Encoding","");
812+
813+ //get the URLs
814+ KEncodingFileDialog::Result result = KEncodingFileDialog::getOpenUrlsAndEncoding(encoding, currentDir, filter, m_ki->mainWindow(), i18n("Open Files"));
815+
816+ Locker lock(&m_autoSaveLock);
817+ //open them
818+ KUrl::List urls = result.URLs;
819+ for (KUrl::List::Iterator i=urls.begin(); i != urls.end(); ++i) {
820+ fileOpen(*i, result.encoding);
821+ }
822+}
823+
824+void Manager::fileSelected(const KFileItem& file)
825+{
826+ Locker lock(&m_autoSaveLock);
827+ fileSelected(file.url());
828+}
829+
830+void Manager::fileSelected(const KileProjectItem * item)
831+{
832+ Locker lock(&m_autoSaveLock);
833+ fileOpen(item->url(), item->encoding());
834+}
835+
836+void Manager::fileSelected(const KUrl& url)
837+{
838+ Locker lock(&m_autoSaveLock);
839+ fileOpen(url, QString());
840+}
841+
842+void Manager::saveURL(const KUrl & url)
843+{
844+ Locker lock(&m_autoSaveLock);
845+ KTextEditor::Document *doc = docFor(url);
846+ if(doc) {
847+ doc->save();
848+ }
849+}
850+
851+void Manager::newDocumentStatus(KTextEditor::Document *doc)
852+{
853+ KILE_DEBUG() << "void Manager::newDocumentStatus(Kate::Document)" << endl;
854+ if(!doc) {
855+ return;
856+ }
857+
858+ //sync terminal
859+ m_ki->texKonsole()->sync();
860+
861+ emit(documentModificationStatusChanged(doc, doc->isModified(), KTextEditor::ModificationInterface::OnDiskUnmodified));
862+}
863+
864+bool Manager::fileSaveAll(bool amAutoSaving, bool disUntitled)
865+{
866+ // this can occur when autosaving should take place when we
867+ // are still busy with it (KIO::NetAccess keeps the event loop running)
868+ if(m_currentlySavingAll) {
869+ return true;
870+ }
871+ m_currentlySavingAll = true;
872+ KTextEditor::View *view = NULL;
873+ QFileInfo fi;
874+ bool oneSaveFailed = false;
875+ KUrl url, backupUrl;
876+
877+ KILE_DEBUG() << "===Kile::fileSaveAll(amAutoSaving = " << amAutoSaving << ",disUntitled = " << disUntitled <<")";
878+
879+ for(int i = 0; i < m_ki->viewManager()->textViewCount(); ++i) {
880+ view = m_ki->viewManager()->textView(i);
881+
882+ if(view && view->document()->isModified()) {
883+ url = view->document()->url();
884+ fi.setFile(url.toLocalFile());
885+
886+ if( (!amAutoSaving && !(disUntitled && url.isEmpty())) // DisregardUntitled is true and we have an untitled doc and don't autosave
887+ || (amAutoSaving && !url.isEmpty()) //don't save untitled documents when autosaving
888+ || (!amAutoSaving && !disUntitled) // both false, so we want to save everything
889+ )
890+ {
891+
892+ KILE_DEBUG() << "The files _" << autosaveWarnings.join(", ") << "_ have autosaveWarnings";
893+
894+ if(amAutoSaving) {
895+ if(!fi.isWritable()) {
896+ if(autosaveWarnings.contains(url.toLocalFile())) {
897+ KILE_DEBUG() << "File " << url.prettyUrl() << " is not writeable (again), trying next file";
898+ continue;
899+ }
900+ else {
901+ autosaveWarnings.append(url.toLocalFile());
902+ KILE_DEBUG() << "File " << url.prettyUrl() << " is not writeable (first time)";
903+ }
904+ }
905+ else {
906+ autosaveWarnings.removeAll(url.toLocalFile());
907+ }
908+ }
909+ if(amAutoSaving && fi.size() > 0) { // the size check ensures that we don't save empty files (to prevent something like #125809 in the future).
910+ KUrl backupUrl = KUrl(url.toLocalFile()+ ".backup");
911+
912+ // patch for secure permissions, slightly modified for kile by Thomas Braun, taken from #103331
913+
914+ // get the right permissions, start with safe default
915+ mode_t perms = 0600;
916+ KIO::UDSEntry fentry;
917+ if (KIO::NetAccess::stat (url, fentry, m_ki->mainWindow())) {
918+ KILE_DEBUG () << "stating successful: " << url.prettyUrl();
919+ KFileItem item (fentry, url);
920+ perms = item.permissions();
921+ }
922+
923+ // first del existing file if any, than copy over the file we have
924+ // failure if a: the existing file could not be deleted, b: the file could not be copied
925+ if((!KIO::NetAccess::exists( backupUrl, false, m_ki->mainWindow())
926+ || KIO::NetAccess::del( backupUrl, m_ki->mainWindow()))
927+ && KIO::NetAccess::file_copy(url, backupUrl, m_ki->mainWindow())) {
928+ KILE_DEBUG() << "backing up successful (" << url.prettyUrl() << " -> "<<backupUrl.prettyUrl() << ")";
929+ }
930+ else {
931+ KILE_DEBUG() << "backing up failed (" << url.prettyUrl() << " -> " << backupUrl.prettyUrl() << ")";
932+ m_ki->logWidget()->printMessage(KileTool::Error,
933+ i18n("The file %1 could not be saved, check the permissions and free disk space.", backupUrl.prettyUrl()),
934+ i18n("Autosave"));
935+ }
936+ }
937+
938+ KILE_DEBUG() << "trying to save: " << url.toLocalFile();
939+ bool saveResult = view->document()->documentSave();
940+ fi.refresh();
941+
942+ if(!saveResult) {
943+ oneSaveFailed = true;
944+ m_ki->logWidget()->printMessage(KileTool::Error,
945+ i18n("Kile encountered problems while saving the file %1. Do you have enough free disk space left?", url.prettyUrl()),
946+ i18n("Saving"));
947+ }
948+ }
949+ }
950+ }
951+
952+ /*
953+ This may look superfluos but actually it is not, in the case of multiple modified docs it ensures that the structure view keeps synchronized with the currentTextView
954+ And if we only have one masterdoc or none nothing goes wrong.
955+ */
956+ emit(updateStructure(false, NULL));
957+ m_currentlySavingAll = false;
958+ return !oneSaveFailed;
959+}
960+
961+void Manager::fileOpen(const KUrl& url, const QString& encoding, int index)
962+{
963+ Locker lock(&m_autoSaveLock);
964+ KILE_DEBUG() << "==Kile::fileOpen==========================";
965+
966+ KILE_DEBUG() << "url is " << url.url();
967+ const KUrl realurl = symlinkFreeURL(url);
968+ KILE_DEBUG() << "symlink free url is " << realurl.url();
969+
970+ bool isopen = m_ki->isOpen(realurl);
971+ if(isopen) {
972+ m_ki->viewManager()->switchToTextView(realurl);
973+ return;
974+ }
975+
976+ KTextEditor::View *view = loadText(m_ki->extensions()->determineDocumentType(realurl), realurl, encoding, true, QString(), QString(), QString(), index);
977+ QList<KileProjectItem*> itemList = itemsFor(realurl);
978+ TextInfo *textInfo = textInfoForURL(realurl);
979+
980+ for(QList<KileProjectItem*>::iterator it = itemList.begin(); it != itemList.end(); ++it) {
981+ (*it)->setInfo(textInfo);
982+ }
983+
984+ if(itemList.isEmpty()) {
985+ emit addToProjectView(realurl);
986+ loadDocumentAndViewSettings(view->document());
987+ }
988+ else if(view) {
989+ KileProjectItem *item = itemList.first();
990+ view->setCursorPosition(KTextEditor::Cursor(item->lineNumber(),item->columnNumber()));
991+ item->loadDocumentAndViewSettings();
992+ }
993+
994+ emit(updateStructure(false, NULL));
995+ emit(updateModeStatus());
996+ // update undefined references in this file
997+ emit(updateReferences(textInfoFor(realurl.toLocalFile())));
998+}
999+
1000+bool Manager::fileSave(KTextEditor::View *view)
1001+{
1002+ Locker lock(&m_autoSaveLock);
1003+ if(!view) {
1004+ view = m_ki->viewManager()->currentTextView();
1005+ }
1006+ if(!view) {
1007+ return false;
1008+ }
1009+ KUrl url = view->document()->url();
1010+ if(url.isEmpty()) { // newly created document
1011+ return fileSaveAs(view);
1012+ }
1013+ else {
1014+ bool ret = view->document()->documentSave();
1015+ emit(updateStructure(false, textInfoFor(view->document())));
1016+ return ret;
1017+ }
1018+}
1019+
1020+bool Manager::fileSaveAs(KTextEditor::View* view)
1021+{
1022+ Locker lock(&m_autoSaveLock);
1023+ if(!view) {
1024+ view = m_ki->viewManager()->currentTextView();
1025+ }
1026+ if(!view) {
1027+ return false;
1028+ }
1029+
1030+ KTextEditor::Document* doc = view->document();
1031+ Q_ASSERT(doc);
1032+ KileDocument::TextInfo* info = textInfoFor(doc);
1033+ Q_ASSERT(info);
1034+ QString startDir = info->url().url();
1035+ KUrl oldURL = info->url();
1036+ if(startDir.isEmpty()) {
1037+ KUrl baseDirectory = info->getBaseDirectory();
1038+ if(baseDirectory.isEmpty()) {
1039+ startDir = "kfiledialog:///KILE_LATEX_SAVE_DIR";
1040+ }
1041+ else {
1042+ startDir = baseDirectory.url();
1043+ }
1044+ }
1045+
1046+ KILE_DEBUG() << "startDir is " << startDir;
1047+
1048+ KEncodingFileDialog::Result result;
1049+ KUrl saveURL;
1050+ while(true) {
1051+ QString filter = info->getFileFilter() + "\n* |" + i18n("All Files");
1052+ result = KEncodingFileDialog::getSaveUrlAndEncoding(doc->encoding(), startDir, filter, m_ki->mainWindow(), i18n("Save File"));
1053+ if(result.URLs.isEmpty() || result.URLs.first().isEmpty()) {
1054+ return false;
1055+ }
1056+ saveURL = result.URLs.first();
1057+ if(info->getType() == KileDocument::LaTeX) {
1058+ saveURL = Info::makeValidTeXURL(saveURL, m_ki->mainWindow(),
1059+ m_ki->extensions()->isTexFile(saveURL), false); // don't check for file existence
1060+ }
1061+ if(KIO::NetAccess::exists(saveURL, true, m_ki->mainWindow())) { // check for writing possibility
1062+ int r = KMessageBox::warningContinueCancel(m_ki->mainWindow(), i18n("A file with the name \"%1\" exists already. Do you want to overwrite it?", saveURL.fileName()), i18n("Overwrite File?"), KGuiItem(i18n("&Overwrite")));
1063+ if(r != KMessageBox::Continue) {
1064+ continue;
1065+ }
1066+ }
1067+ break;
1068+ }
1069+ doc->setEncoding(result.encoding);
1070+ if(!doc->saveAs(saveURL)) {
1071+ return false;
1072+ }
1073+ if(oldURL != saveURL) {
1074+ if(info->isDocumentTypePromotionAllowed()) {
1075+ recreateTextDocumentInfo(info);
1076+ info = textInfoFor(doc);
1077+ }
1078+ m_ki->structureWidget()->updateUrl(info);
1079+ emit addToRecentFiles(saveURL);
1080+ emit addToProjectView(doc->url());
1081+ }
1082+ return true;
1083+}
1084+
1085+void Manager::fileSaveCopyAs()
1086+{
1087+ Locker lock(&m_autoSaveLock);
1088+ KTextEditor::Document *doc= m_ki->activeTextDocument();
1089+ KTextEditor::View *view = NULL;
1090+ if(doc) {
1091+ KileDocument::TextInfo *originalInfo = textInfoFor(doc);
1092+
1093+ if(!originalInfo) {
1094+ return;
1095+ }
1096+
1097+ view = createDocumentWithText(doc->text(),originalInfo->getType());
1098+
1099+ KileDocument::TextInfo *newInfo = textInfoFor(view->document());
1100+
1101+ if(originalInfo->url().isEmpty()) { // untitled doc
1102+ newInfo->setBaseDirectory(m_ki->fileSelector()->currentUrl().toLocalFile());
1103+ }
1104+ else {
1105+ newInfo->setBaseDirectory(originalInfo->url().toLocalFile());
1106+ }
1107+
1108+ fileSaveAs(view);
1109+
1110+ doc = view->document();
1111+ if(doc && !doc->isModified()) { // fileSaveAs was successful
1112+ fileClose(doc);
1113+ }
1114+ }
1115+}
1116+
1117+bool Manager::fileCloseAllOthers(KTextEditor::View *currentView)
1118+{
1119+ Locker lock(&m_autoSaveLock);
1120+ QAction *action = m_ki->mainWindow()->action("file_close_all_others");
1121+ // the 'data' property can be set by the view manager
1122+ QVariant var = action->data();
1123+ if(!currentView && var.isValid()) {
1124+ // the 'data' property for the relevant actions is cleared
1125+ // inside the view manager
1126+ currentView = var.value<KTextEditor::View*>();
1127+ }
1128+ if(!currentView) {
1129+ currentView = m_ki->viewManager()->currentTextView();
1130+ }
1131+ if(!currentView) {
1132+ return false;
1133+ }
1134+
1135+ QList<KTextEditor::View*> viewList;
1136+ for(int i = 0; i < m_ki->viewManager()->textViewCount(); ++i) {
1137+ KTextEditor::View *view = m_ki->viewManager()->textView(i);
1138+ if(currentView == view) {
1139+ continue;
1140+ }
1141+ viewList.push_back(view);
1142+
1143+ }
1144+ for(QList<KTextEditor::View*>::iterator it = viewList.begin();
1145+ it != viewList.end(); ++it) {
1146+ if (!fileClose(*it)) {
1147+ return false;
1148+ }
1149+ }
1150+ return true;
1151+}
1152+
1153+bool Manager::fileCloseAll()
1154+{
1155+ Locker lock(&m_autoSaveLock);
1156+ KTextEditor::View * view = m_ki->viewManager()->currentTextView();
1157+
1158+ //assumes one view per doc here
1159+ while(m_ki->viewManager()->textViewCount() > 0) {
1160+ view = m_ki->viewManager()->textView(0);
1161+ if (!fileClose(view->document())) {
1162+ return false;
1163+ }
1164+ }
1165+ return true;
1166+}
1167+
1168+bool Manager::fileClose(const KUrl & url)
1169+{
1170+ KTextEditor::Document *doc = docFor(url);
1171+ if(!doc) {
1172+ return true;
1173+ }
1174+ else {
1175+ return fileClose(doc);
1176+ }
1177+}
1178+
1179+bool Manager::fileClose(KTextEditor::View *view)
1180+{
1181+ QAction *action = m_ki->mainWindow()->action("file_close");
1182+ // the 'data' property can be set by the view manager
1183+ QVariant var = action->data();
1184+ if(!view && var.isValid()) {
1185+ view = var.value<KTextEditor::View*>();
1186+ // the 'data' property for the relevant actions is cleared
1187+ // inside the view manager
1188+ }
1189+ if(!view) {
1190+ view = m_ki->viewManager()->currentTextView();
1191+ }
1192+ if(!view) {
1193+ return false;
1194+ }
1195+ return fileClose(view->document());
1196+}
1197+
1198+bool Manager::fileClose(KTextEditor::Document *doc /* = 0L*/, bool closingproject /*= false*/)
1199+{
1200+ KILE_DEBUG() << "==Kile::fileClose==========================";
1201+
1202+ if(!doc) {
1203+ doc = m_ki->activeTextDocument();
1204+ }
1205+
1206+ if(!doc) {
1207+ return true;
1208+ }
1209+
1210+ Locker lock(&m_autoSaveLock);
1211+
1212+ //FIXME: remove from docinfo map, remove from dirwatch
1213+ KILE_DEBUG() << "doc->url().toLocalFile()=" << doc->url().toLocalFile();
1214+
1215+ const KUrl url = doc->url();
1216+
1217+ TextInfo *docinfo= textInfoFor(doc);
1218+ if(!docinfo) {
1219+ kWarning() << "no DOCINFO for " << url.url();
1220+ return true;
1221+ }
1222+ bool inProject = false;
1223+ QList<KileProjectItem*> items = itemsFor(docinfo);
1224+ for(QList<KileProjectItem*>::iterator it = items.begin(); it != items.end(); ++it) {
1225+ KileProjectItem *item = *it;
1226+
1227+ //FIXME: refactor here
1228+ if(item && doc) {
1229+ storeProjectItem(item, doc);
1230+ inProject = true;
1231+ }
1232+ }
1233+
1234+ if(!inProject) {
1235+ KILE_DEBUG() << "not in project";
1236+ saveDocumentAndViewSettings(doc);
1237+ }
1238+
1239+ if(doc->closeUrl()) {
1240+ // docinfo may have been recreated from 'Untitled' doc to a named doc
1241+ if(url.isEmpty()) {
1242+ docinfo= textInfoFor(doc);
1243+ }
1244+
1245+ if(KileConfig::cleanUpAfterClose()) {
1246+ cleanUpTempFiles(url, true); // yes we pass here url and not docinfo->url()
1247+ }
1248+
1249+ //FIXME: use signal/slot
1250+ if( doc->views().count() > 0){
1251+ m_ki->viewManager()->removeView(doc->views().first());
1252+ }
1253+ //remove the decorations
1254+
1255+ trashDoc(docinfo, doc);
1256+ m_ki->structureWidget()->clean(docinfo);
1257+ removeTextDocumentInfo(docinfo, closingproject);
1258+
1259+ emit removeFromProjectView(url);
1260+ emit updateModeStatus();
1261+ }
1262+ else {
1263+ return false;
1264+ }
1265+
1266+ return true;
1267+}
1268+
1269+void Manager::buildProjectTree(const KUrl & url)
1270+{
1271+ KileProject * project = projectFor(url);
1272+
1273+ if (project) {
1274+ buildProjectTree(project);
1275+ }
1276+}
1277+
1278+void Manager::buildProjectTree(KileProject *project)
1279+{
1280+ if(!project) {
1281+ project = activeProject();
1282+ }
1283+
1284+ if(!project) {
1285+ project = selectProject(i18n("Refresh Project Tree"));
1286+ }
1287+
1288+ if (project) {
1289+ //TODO: update structure for all docs
1290+ project->buildProjectTree();
1291+ }
1292+ else if (m_projects.count() == 0) {
1293+ KMessageBox::error(m_ki->mainWindow(), i18n("The current document is not associated to a project. Please activate a document that is associated to the project you want to build the tree for, then choose Refresh Project Tree again."),i18n( "Could Not Refresh Project Tree"));
1294+ }
1295+}
1296+
1297+void Manager::projectNew()
1298+{
1299+ KileNewProjectDlg *dlg = new KileNewProjectDlg(m_ki->templateManager(), m_ki->extensions(), m_ki->mainWindow());
1300+
1301+ if (dlg->exec())
1302+ {
1303+ Locker lock(&m_autoSaveLock);
1304+ KileProject *project = dlg->project();
1305+
1306+ //add the project file to the project
1307+ KileProjectItem *item = new KileProjectItem(project, project->url());
1308+ item->setOpenState(false);
1309+ projectOpenItem(item);
1310+
1311+ if(dlg->createNewFile()){
1312+ QString filename = dlg->file();
1313+
1314+ //create the new document and fill it with the template
1315+ KTextEditor::View *view = loadTemplate(dlg->getSelection());
1316+
1317+ if(view) {
1318+ //derive the URL from the base url of the project
1319+ KUrl url = project->baseURL();
1320+ url.addPath(filename);
1321+
1322+ TextInfo *docinfo = textInfoFor(view->document());
1323+
1324+ //save the new file
1325+ view->document()->saveAs(url);
1326+ emit(documentModificationStatusChanged(view->document(),
1327+ false, KTextEditor::ModificationInterface::OnDiskUnmodified));
1328+
1329+ //add this file to the project
1330+ item = new KileProjectItem(project, url);
1331+ //project->add(item);
1332+ mapItem(docinfo, item);
1333+
1334+ //docinfo->updateStruct(m_kwStructure->level());
1335+ emit(updateStructure(false, docinfo));
1336+ }
1337+ }
1338+
1339+ project->buildProjectTree();
1340+ //project->save();
1341+ addProject(project);
1342+ emit(updateModeStatus());
1343+ emit(addToRecentProjects(project->url()));
1344+ }
1345+}
1346+
1347+void Manager::addProject(KileProject *project)
1348+{
1349+ Locker lock(&m_autoSaveLock);
1350+ KILE_DEBUG() << "==void Manager::addProject(const KileProject *project)==========";
1351+ m_projects.append(project);
1352+ KILE_DEBUG() << "\tnow " << m_projects.count() << " projects";
1353+ emit addToProjectView(project);
1354+ connect(project, SIGNAL(projectTreeChanged(const KileProject *)), this, SIGNAL(projectTreeChanged(const KileProject *)));
1355+}
1356+
1357+KileProject* Manager::selectProject(const QString& caption)
1358+{
1359+ QStringList list;
1360+ for(QList<KileProject*>::iterator it = m_projects.begin(); it != m_projects.end(); ++it) {
1361+ list.append((*it)->name());
1362+ }
1363+
1364+ KileProject *project = NULL;
1365+ QString name;
1366+ if (list.count() > 1) {
1367+ KileListSelector *dlg = new KileListSelector(list, caption, i18n("Select Project"), m_ki->mainWindow());
1368+ if (dlg->exec())
1369+ {
1370+ name = list[dlg->currentItem()];
1371+ }
1372+ delete dlg;
1373+ }
1374+ else if (list.count() == 0) {
1375+ return NULL;
1376+ }
1377+ else {
1378+ name = m_projects.first()->name();
1379+ }
1380+
1381+ project = projectFor(name);
1382+
1383+ return project;
1384+}
1385+
1386+void Manager::addToProject(const KUrl & url)
1387+{
1388+ Locker lock(&m_autoSaveLock);
1389+ KILE_DEBUG() << "===Kile::addToProject(const KUrl & url =" << url.url() << ")";
1390+
1391+ KileProject *project = selectProject(i18n("Add to Project"));
1392+
1393+ if (project) {
1394+ addToProject(project, url);
1395+ }
1396+}
1397+
1398+void Manager::addToProject(KileProject* project, const KUrl & url)
1399+{
1400+ Locker lock(&m_autoSaveLock);
1401+ const KUrl realurl = symlinkFreeURL(url);
1402+ QFileInfo fi(realurl.toLocalFile());
1403+
1404+ if (project->contains(realurl)) {
1405+ m_ki->logWidget()->printMessage(KileTool::Info,
1406+ i18n("The file %1 is already member of the project %2", realurl.fileName(), project->name()),
1407+ i18n("Add to Project"));
1408+ return;
1409+ }
1410+ else if(!fi.exists() || !fi.isReadable())
1411+ {
1412+ m_ki->logWidget()->printMessage(KileTool::Info,
1413+ i18n("The file %1 can not be added because it does not exist or is not readable", realurl.fileName()),
1414+ i18n("Add to Project"));
1415+ return;
1416+ }
1417+
1418+ KileProjectItem *item = new KileProjectItem(project, realurl);
1419+ item->setOpenState(m_ki->isOpen(realurl));
1420+ projectOpenItem(item);
1421+ emit addToProjectView(item);
1422+ buildProjectTree(project);
1423+}
1424+
1425+void Manager::removeFromProject(KileProjectItem *item)
1426+{
1427+ Locker lock(&m_autoSaveLock);
1428+ if (item && item->project()) {
1429+ KILE_DEBUG() << "\tprojecturl = " << item->project()->url().toLocalFile() << ", url = " << item->url().toLocalFile();
1430+
1431+ if (item->project()->url() == item->url()) {
1432+ KMessageBox::error(m_ki->mainWindow(), i18n("This file is the project file, which holds all the information about your project. As such, it cannot be removed from the project."), i18n("Cannot Remove File From Project"));
1433+ return;
1434+ }
1435+
1436+ emit removeItemFromProjectView(item, m_ki->isOpen(item->url()));
1437+
1438+ KileProject *project = item->project();
1439+ project->remove(item);
1440+
1441+ // update undefined references in all project files
1442+ updateProjectReferences(project);
1443+ project->buildProjectTree();
1444+ }
1445+}
1446+
1447+void Manager::projectOpenItem(KileProjectItem *item, bool openProjectItemViews)
1448+{
1449+ Locker lock(&m_autoSaveLock);
1450+ KILE_DEBUG() << "==Kile::projectOpenItem==========================";
1451+ KILE_DEBUG() << "\titem:" << item->url().toLocalFile();
1452+
1453+ if (m_ki->isOpen(item->url())) { //remove item from projectview (this file was opened before as a normal file)
1454+ emit removeFromProjectView(item->url());
1455+ }
1456+
1457+ KTextEditor::View *view = loadItem(m_ki->extensions()->determineDocumentType(item->url()), item, QString(), openProjectItemViews);
1458+ if(item->getInfo()) { // make sure that the item has been parsed, even if it isn't shown
1459+ // this is necessary to identify the correct LaTeX root document (bug 233667)
1460+ m_ki->structureWidget()->update(item->getInfo());
1461+ }
1462+
1463+ if((!item->isOpen()) && !view && item->getInfo()) { //doc shouldn't be displayed, trash the doc
1464+ trashDoc(item->getInfo());
1465+ }
1466+ else if(view) {
1467+ view->setCursorPosition(KTextEditor::Cursor(item->lineNumber(), item->columnNumber()));
1468+ item->loadDocumentAndViewSettings();
1469+ }
1470+
1471+ //oops, doc apparently was open while the project settings wants it closed, don't trash it the doc, update openstate instead
1472+ if ((!item->isOpen()) && view) {
1473+ item->setOpenState(true);
1474+ }
1475+}
1476+
1477+KileProject* Manager::projectOpen(const KUrl & url, int step, int max, bool openProjectItemViews)
1478+{
1479+ Locker lock(&m_autoSaveLock);
1480+ KILE_DEBUG() << "==Kile::projectOpen==========================";
1481+ KILE_DEBUG() << "\tfilename: " << url.fileName();
1482+
1483+ const KUrl realurl = symlinkFreeURL(url);
1484+
1485+ if(m_ki->projectIsOpen(realurl)) {
1486+ if(m_progressDialog) {
1487+ m_progressDialog->hide();
1488+ }
1489+
1490+ KMessageBox::information(m_ki->mainWindow(), i18n("The project you tried to open is already opened. If you wanted to reload the project, close the project before you re-open it."),i18n("Project Already Open"));
1491+ return NULL;
1492+ }
1493+
1494+ QFileInfo fi(realurl.toLocalFile());
1495+ if(!fi.isReadable()) {
1496+ if(m_progressDialog) {
1497+ m_progressDialog->hide();
1498+ }
1499+
1500+ if (KMessageBox::warningYesNo(m_ki->mainWindow(), i18n("The project file for the project \"%1\" does not exist or is not readable. Remove this project from the recent projects list?", url.prettyUrl()), i18n("Could Not Load Project File")) == KMessageBox::Yes) {
1501+ emit(removeFromRecentProjects(realurl));
1502+ }
1503+ return NULL;
1504+ }
1505+
1506+ if(!m_progressDialog) {
1507+ createProgressDialog();
1508+ }
1509+
1510+ m_progressDialog->show();
1511+
1512+ KileProject *kp = new KileProject(realurl,m_ki->extensions());
1513+
1514+ if(kp->isInvalid()) {
1515+ if(m_progressDialog) {
1516+ m_progressDialog->hide();
1517+ }
1518+ delete kp;
1519+ return NULL;
1520+ }
1521+
1522+ emit(addToRecentProjects(realurl));
1523+
1524+ QList<KileProjectItem*> list = kp->items();
1525+
1526+ int project_steps = list.count() + 1;
1527+ m_progressDialog->progressBar()->setMaximum(project_steps * max);
1528+ project_steps *= step;
1529+ m_progressDialog->progressBar()->setValue(project_steps);
1530+
1531+ // open the project files in the correct order
1532+ QVector<KileProjectItem*> givenPositionVector(list.count(), NULL);
1533+ QList<KileProjectItem*> notCorrectlyOrderedList;
1534+ for(QList<KileProjectItem*>::iterator it = list.begin(); it != list.end(); ++it) {
1535+ KileProjectItem *item = *it;
1536+ int order = item->order();
1537+
1538+ if(order >= 0 && order >= list.count()) {
1539+ order = -1;
1540+ }
1541+ if(!item->isOpen() || order < 0 || givenPositionVector[order] != NULL) {
1542+ notCorrectlyOrderedList.push_back(item);
1543+ }
1544+ else {
1545+ givenPositionVector[order] = item;
1546+ }
1547+ }
1548+
1549+ QList<KileProjectItem*> orderedList;
1550+ for(int i = 0; i < givenPositionVector.size(); ++i) {
1551+ KileProjectItem *item = givenPositionVector[i];
1552+ if(item) {
1553+ orderedList.push_back(item);
1554+ }
1555+ }
1556+ for(QList<KileProjectItem*>::iterator i = notCorrectlyOrderedList.begin(); i != notCorrectlyOrderedList.end(); ++i) {
1557+ orderedList.push_back(*i);
1558+ }
1559+
1560+ unsigned int counter = 0;
1561+ for (QList<KileProjectItem*>::iterator i = orderedList.begin(); i != orderedList.end(); ++i) {
1562+ projectOpenItem(*i, openProjectItemViews);
1563+ m_progressDialog->progressBar()->setValue(counter + project_steps);
1564+ kapp->processEvents();
1565+ ++counter;
1566+ }
1567+
1568+ kp->buildProjectTree();
1569+ addProject(kp);
1570+
1571+ emit(updateStructure(false, NULL));
1572+ emit(updateModeStatus());
1573+ // update undefined references in all project files
1574+ updateProjectReferences(kp);
1575+
1576+ if (step == (max - 1)) {
1577+ m_progressDialog->hide();
1578+ }
1579+
1580+ m_ki->viewManager()->switchToTextView(kp->lastDocument());
1581+
1582+ return kp;
1583+}
1584+
1585+// as all labels are gathered in the project, we can check for unsolved references
1586+void Manager::updateProjectReferences(KileProject *project)
1587+{
1588+ QList<KileProjectItem*> list = project->items();
1589+ for(QList<KileProjectItem*>::iterator it = list.begin(); it != list.end(); ++it) {
1590+ emit(updateReferences((*it)->getInfo()));
1591+ }
1592+}
1593+
1594+KileProject* Manager::projectOpen()
1595+{
1596+ KILE_DEBUG() << "==Kile::projectOpen==========================";
1597+ KUrl url = KFileDialog::getOpenUrl( KileConfig::defaultProjectLocation(), i18n("*.kilepr|Kile Project Files\n*|All Files"), m_ki->mainWindow(), i18n("Open Project") );
1598+
1599+ if(!url.isEmpty()) {
1600+ return projectOpen(url);
1601+ }
1602+ else {
1603+ return NULL;
1604+ }
1605+}
1606+
1607+
1608+void Manager::projectSave(KileProject *project /* = 0 */)
1609+{
1610+ Locker lock(&m_autoSaveLock);
1611+ KILE_DEBUG() << "==Kile::projectSave==========================";
1612+ if (!project) {
1613+ //find the project that corresponds to the active doc
1614+ project= activeProject();
1615+ }
1616+
1617+ if(!project) {
1618+ project = selectProject(i18n("Save Project"));
1619+ }
1620+
1621+ if(project) {
1622+ QList<KileProjectItem*> list = project->items();
1623+ KTextEditor::Document *doc = NULL;
1624+ KileProjectItem *item = NULL;
1625+ TextInfo *docinfo = NULL;
1626+
1627+ // determine the order in which the project items are opened
1628+ QVector<KileProjectItem*> viewPositionVector(m_ki->viewManager()->getTabCount(), NULL);
1629+ for(QList<KileProjectItem*>::iterator i = list.begin(); i != list.end(); ++i) {
1630+ docinfo = (*i)->getInfo();
1631+ if(docinfo) {
1632+ KTextEditor::View *view = m_ki->viewManager()->textView(docinfo);
1633+ if(view) {
1634+ int position = m_ki->viewManager()->getIndexOf(view);
1635+ if(position >= 0 && position < viewPositionVector.size()) {
1636+ viewPositionVector[position] = *i;
1637+ }
1638+ }
1639+ }
1640+ }
1641+ int position = 0;
1642+ for(int i = 0; i < viewPositionVector.size(); ++i) {
1643+ if(viewPositionVector[i] != NULL) {
1644+ viewPositionVector[i]->setOrder(position);
1645+ ++position;
1646+ }
1647+ }
1648+
1649+ //update the open-state of the items
1650+ for (QList<KileProjectItem*>::iterator i = list.begin(); i != list.end(); ++i) {
1651+ item = *i;
1652+ KILE_DEBUG() << "\tsetOpenState(" << (*i)->url().toLocalFile() << ") to " << m_ki->isOpen(item->url());
1653+ item->setOpenState(m_ki->isOpen(item->url()));
1654+ docinfo = item->getInfo();
1655+
1656+ if(docinfo) {
1657+ doc = docinfo->getDoc();
1658+ }
1659+ if(doc) {
1660+ storeProjectItem(item, doc);
1661+ }
1662+
1663+ doc = NULL;
1664+ docinfo = NULL;
1665+ }
1666+
1667+ project->save();
1668+ }
1669+ else {
1670+ KMessageBox::error(m_ki->mainWindow(), i18n("The current document is not associated to a project. Please activate a document that is associated to the project you want to save, then choose Save Project again."),i18n( "Could Determine Active Project"));
1671+ }
1672+}
1673+
1674+void Manager::projectAddFiles(const KUrl & url)
1675+{
1676+ Locker lock(&m_autoSaveLock);
1677+ KileProject *project = projectFor(url);
1678+
1679+ if (project) {
1680+ projectAddFiles(project,url);
1681+ }
1682+}
1683+
1684+void Manager::projectAddFiles(KileProject *project,const KUrl & fileUrl)
1685+{
1686+ Locker lock(&m_autoSaveLock);
1687+ KILE_DEBUG() << "==Kile::projectAddFiles()==========================";
1688+ if(project == 0) {
1689+ project = activeProject();
1690+ }
1691+
1692+ if(project == 0) {
1693+ project = selectProject(i18n("Add Files to Project"));
1694+ }
1695+
1696+ if (project) {
1697+ QString currentDir;
1698+ if(fileUrl.isEmpty())
1699+ currentDir=project->url().directory();
1700+ else
1701+ currentDir=fileUrl.directory();
1702+
1703+ KILE_DEBUG() << "currentDir is " << currentDir;
1704+ KFileDialog *dlg = new KFileDialog(currentDir, i18n("*|All Files"), m_ki->mainWindow());
1705+ dlg->setModal(true);
1706+ KPushButton* okButton = dlg->okButton();
1707+ okButton->setText(i18n("Add"));
1708+ dlg->setCaption(i18n("Add Files"));
1709+ dlg->setMode(KFile::Files | KFile::ExistingOnly);
1710+
1711+ if(dlg->exec()) {
1712+ KUrl::List urls = dlg->selectedUrls();
1713+ for(int i=0; i < urls.count(); ++i) {
1714+ addToProject(project, urls[i]);
1715+ }
1716+ // update undefined references in all project files
1717+ updateProjectReferences(project);
1718+ }
1719+ delete dlg;
1720+
1721+ //open them
1722+ }
1723+ else if (m_projects.count() == 0) {
1724+ KMessageBox::error(m_ki->mainWindow(), i18n("There are no projects opened. Please open the project you want to add files to, then choose Add Files again."),i18n( "Could Not Determine Active Project"));
1725+ }
1726+}
1727+
1728+void Manager::toggleArchive(KileProjectItem *item)
1729+{
1730+ item->setArchive(!item->archive());
1731+}
1732+
1733+void Manager::projectOptions(const KUrl & url)
1734+{
1735+ KileProject *project = projectFor(url);
1736+
1737+ if (project) {
1738+ projectOptions(project);
1739+ }
1740+}
1741+
1742+void Manager::projectOptions(KileProject *project /* = 0*/)
1743+{
1744+ KILE_DEBUG() << "==Kile::projectOptions==========================";
1745+ if(!project) {
1746+ project = activeProject();
1747+ }
1748+
1749+ if(!project) {
1750+ project = selectProject(i18n("Project Options For"));
1751+ }
1752+
1753+ if (project) {
1754+ KILE_DEBUG() << "\t" << project->name();
1755+ KileProjectOptionsDlg *dlg = new KileProjectOptionsDlg(project, m_ki->extensions(), m_ki->mainWindow());
1756+ dlg->exec();
1757+ }
1758+ else if (m_projects.count() == 0) {
1759+ KMessageBox::error(m_ki->mainWindow(), i18n("The current document is not associated to a project. Please activate a document that is associated to the project you want to modify, then choose Project Options again."),i18n( "Could Not Determine Active Project"));
1760+ }
1761+}
1762+
1763+bool Manager::projectCloseAll()
1764+{
1765+ Locker lock(&m_autoSaveLock);
1766+ KILE_DEBUG() << "==Kile::projectCloseAll==========================";
1767+
1768+ for(QList<KileProject*>::iterator it = m_projects.begin(); it != m_projects.end(); ++it) {
1769+ if(!projectClose((*it)->url())) {
1770+ return false;
1771+ }
1772+ }
1773+
1774+ return true;
1775+}
1776+
1777+bool Manager::projectClose(const KUrl & url)
1778+{
1779+ Locker lock(&m_autoSaveLock);
1780+ KILE_DEBUG() << "==Kile::projectClose==========================";
1781+ KileProject *project = 0;
1782+
1783+ if (url.isEmpty()) {
1784+ project = activeProject();
1785+
1786+ if (!project) {
1787+ project = selectProject(i18n("Close Project"));
1788+ }
1789+ }
1790+ else {
1791+ project = projectFor(url);
1792+ }
1793+
1794+ if(project) {
1795+ KILE_DEBUG() << "\tclosing:" << project->name();
1796+ project->setLastDocument(m_ki->getName());
1797+
1798+ projectSave(project);
1799+
1800+ QList<KileProjectItem*> list = project->items();
1801+
1802+ bool close = true;
1803+ KTextEditor::Document *doc = NULL;
1804+ TextInfo *docinfo = NULL;
1805+ for(QList<KileProjectItem*>::iterator it = list.begin(); it != list.end(); ++it) {
1806+ KileProjectItem *item = *it;
1807+
1808+ doc = NULL;
1809+ docinfo = item->getInfo();
1810+ if (docinfo) {
1811+ doc = docinfo->getDoc();
1812+ }
1813+ else {
1814+ continue;
1815+ }
1816+ if (doc) {
1817+ KILE_DEBUG() << "\t\tclosing item " << doc->url().toLocalFile();
1818+ bool r = fileClose(doc, true);
1819+ close = close && r;
1820+ if (!close) {
1821+ break;
1822+ }
1823+ }
1824+ else {
1825+ // we still need to delete the TextInfo object
1826+ removeTextDocumentInfo(docinfo, true);
1827+ }
1828+ }
1829+
1830+ if (close) {
1831+ m_projects.removeAll(project);
1832+ emit removeFromProjectView(project);
1833+ delete project;
1834+ emit(updateModeStatus());
1835+ return true;
1836+ }
1837+ else
1838+ return false;
1839+ }
1840+ else if (m_projects.count() == 0)
1841+ KMessageBox::error(m_ki->mainWindow(), i18n("The current document is not associated to a project. Please activate a document that is associated to the project you want to close, then choose Close Project again."),i18n( "Could Not Close Project"));
1842+
1843+ return true;
1844+}
1845+
1846+void Manager::storeProjectItem(KileProjectItem *item, KTextEditor::Document *doc)
1847+{
1848+ Locker lock(&m_autoSaveLock);
1849+ KILE_DEBUG() << "===Kile::storeProjectItem==============";
1850+ KILE_DEBUG() << "\titem = " << item << ", doc = " << doc;
1851+ item->setEncoding(doc->encoding());
1852+ item->setMode(doc->mode());
1853+ item->setHighlight(doc->highlightingMode());
1854+ uint l = 0, c = 0;
1855+ QList<KTextEditor::View*> viewList = doc->views();
1856+ if(viewList.size() > 0) {
1857+ KTextEditor::View *view = static_cast<KTextEditor::View*>(viewList.first());
1858+
1859+ if (view) {
1860+ KTextEditor::Cursor cursor = view->cursorPosition();
1861+ l = cursor.line();
1862+ c = cursor.column();
1863+ }
1864+ }
1865+ item->setLineNumber(l);
1866+ item->setColumnNumber(c);
1867+ item->saveDocumentAndViewSettings();
1868+}
1869+
1870+void Manager::cleanUpTempFiles(const KUrl &url, bool silent)
1871+{
1872+ Locker lock(&m_autoSaveLock);
1873+ KILE_DEBUG() << "===void Manager::cleanUpTempFiles(const KUrl " << url.toLocalFile() << ", bool " << silent << ")===";
1874+
1875+ if( url.isEmpty() )
1876+ return;
1877+
1878+ QStringList extlist;
1879+ QFileInfo fi(url.toLocalFile());
1880+ const QStringList templist = KileConfig::cleanUpFileExtensions().split(' ');
1881+ const QString fileName = fi.fileName();
1882+ const QString dirPath = fi.absolutePath();
1883+ const QString baseName = fi.completeBaseName();
1884+
1885+ for (int i = 0; i < templist.count(); ++i) {
1886+ fi.setFile( dirPath + '/' + baseName + templist[i] );
1887+ if(fi.exists()) {
1888+ extlist.append(templist[i]);
1889+ }
1890+ }
1891+
1892+ if(!silent && fileName.isEmpty()) {
1893+ return;
1894+ }
1895+
1896+ if (!silent && extlist.count() > 0) {
1897+ KILE_DEBUG() << "not silent";
1898+ KileDialog::Clean *dialog = new KileDialog::Clean(m_ki->mainWindow(), fileName, extlist);
1899+ if(dialog->exec()) {
1900+ extlist = dialog->getCleanlist();
1901+ }
1902+ else {
1903+ delete dialog;
1904+ return;
1905+ }
1906+
1907+ delete dialog;
1908+ }
1909+
1910+ if(extlist.count() == 0) {
1911+ m_ki->logWidget()->printMessage(KileTool::Warning, i18n("Nothing to clean for %1", fileName),
1912+ i18n("Clean"));
1913+ }
1914+ else {
1915+ for(int i = 0; i < extlist.count(); ++i) {
1916+ QFile file(dirPath + '/' + baseName + extlist[i]);
1917+ KILE_DEBUG() << "About to remove file = " << file.fileName();
1918+ file.remove();
1919+ }
1920+ m_ki->logWidget()->printMessage(KileTool::Info,
1921+ i18n("Cleaning %1: %2", fileName, extlist.join(" ")),
1922+ i18n("Clean"));
1923+ }
1924+}
1925+
1926+void Manager::openDroppedURLs(QDropEvent *e) {
1927+ Locker lock(&m_autoSaveLock);
1928+ KUrl::List urls = KUrl::List::fromMimeData(e->mimeData());
1929+ Extensions *extensions = m_ki->extensions();
1930+
1931+ for(KUrl::List::iterator i = urls.begin(); i != urls.end(); ++i) {
1932+ KUrl url = *i;
1933+ if(extensions->isProjectFile(url)) {
1934+ projectOpen(url);
1935+ }
1936+ else {
1937+ fileOpen(url);
1938+ }
1939+ }
1940+}
1941+
1942+void Manager::reloadXMLOnAllDocumentsAndViews()
1943+{
1944+ for(QList<TextInfo*>::iterator it = m_textInfoList.begin(); it != m_textInfoList.end(); ++it) {
1945+ KTextEditor::Document *doc = (*it)->getDoc();
1946+ // FIXME: 'doc' can be null, for example if it belongs to a project item
1947+ // which has been closed, but this should be improved in the sense
1948+ // that 'm_textInfoList' should only contain 'TextInfo' objects which
1949+ // contain valid pointers to 'KTextEditor::Document' objects.
1950+ if(!doc) {
1951+ continue;
1952+ }
1953+ doc->reloadXML();
1954+ QList<KTextEditor::View*> views = doc->views();
1955+ for(QList<KTextEditor::View*>::iterator viewIt = views.begin(); viewIt != views.end(); ++viewIt) {
1956+ (*viewIt)->reloadXML();
1957+ }
1958+ }
1959+}
1960+
1961+// Show all opened projects and switch to another one, if you want
1962+
1963+void Manager::projectShow()
1964+{
1965+ Locker lock(&m_autoSaveLock);
1966+ if(m_projects.count() <= 1) {
1967+ return;
1968+ }
1969+
1970+ // select the new project
1971+ KileProject *project = selectProject(i18n("Switch Project"));
1972+ if(!project || project==activeProject()) {
1973+ return;
1974+ }
1975+
1976+ // get last opened document
1977+ const KUrl lastdoc = project->lastDocument();
1978+ KileProjectItem *docitem = (!lastdoc.isEmpty()) ? itemFor(lastdoc, project) : NULL;
1979+
1980+ // if not, we search for the first opened tex file of this project
1981+ // if no file is opened, we take the first tex file mentioned in the list
1982+ KileProjectItem *first_texitem = NULL;
1983+ if(!docitem) {
1984+ QList<KileProjectItem*> list = project->items();
1985+ for(QList<KileProjectItem*>::iterator it = list.begin(); it != list.end(); ++it) {
1986+ KileProjectItem *item = *it;
1987+
1988+ QString itempath = item->path();
1989+
1990+ // called from KAction 'Show projects...': find the first opened
1991+ // LaTeX document or, if that fails, any other opened file
1992+ QStringList extlist = (m_ki->extensions()->latexDocuments() + ' ' + m_ki->extensions()->latexPackages()).split(' ');
1993+ for(QStringList::Iterator it=extlist.begin(); it!=extlist.end(); ++it) {
1994+ if(itempath.indexOf( (*it), -(*it).length() ) >= 0) {
1995+ if (m_ki->isOpen(item->url())) {
1996+ docitem = item;
1997+ break;
1998+ }
1999+ else if(!first_texitem) {
2000+ first_texitem = item;
2001+ }
2002+ }
2003+ }
2004+ if(docitem) {
2005+ break;
2006+ }
2007+ }
2008+ }
2009+
2010+ // did we find one opened file or must we take the first entry
2011+ if(!docitem) {
2012+ if(!first_texitem) {
2013+ return;
2014+ }
2015+ docitem = first_texitem;
2016+ }
2017+
2018+ // ok, we can switch to another project now
2019+ if (m_ki->isOpen(docitem->url())) {
2020+ m_ki->viewManager()->switchToTextView(docitem->url());
2021+ }
2022+ else {
2023+ fileOpen(docitem->url(), docitem->encoding());
2024+ }
2025+}
2026+
2027+void Manager::projectRemoveFiles()
2028+{
2029+ Locker lock(&m_autoSaveLock);
2030+ QList<KileProjectItem*> itemsList = selectProjectFileItems(i18n("Select Files to Remove"));
2031+ if(itemsList.count() > 0) {
2032+ for(QList<KileProjectItem*>::iterator it = itemsList.begin(); it != itemsList.end(); ++it) {
2033+ removeFromProject(*it);
2034+ }
2035+ }
2036+}
2037+
2038+void Manager::projectShowFiles()
2039+{
2040+ Locker lock(&m_autoSaveLock);
2041+ KileProjectItem *item = selectProjectFileItem( i18n("Select File") );
2042+ if(item) {
2043+ if (item->type() == KileProjectItem::ProjectFile) {
2044+ dontOpenWarning(item, i18n("Show Project Files"), i18n("project configuration file"));
2045+ }
2046+ else if(item->type() == KileProjectItem::Image) {
2047+ dontOpenWarning(item, i18n("Show Project Files"), i18n("graphics file"));
2048+ }
2049+ else { // ok, we can switch to another file
2050+ if (m_ki->isOpen(item->url())) {
2051+ m_ki->viewManager()->switchToTextView(item->url());
2052+ }
2053+ else {
2054+ fileOpen(item->url(), item->encoding() );
2055+ }
2056+ }
2057+ }
2058+}
2059+
2060+void Manager::projectOpenAllFiles()
2061+{
2062+ Locker lock(&m_autoSaveLock);
2063+ KileProject *project = selectProject(i18n("Select Project"));
2064+ if(project) {
2065+ projectOpenAllFiles(project->url());
2066+ }
2067+}
2068+
2069+void Manager::projectOpenAllFiles(const KUrl & url)
2070+{
2071+ Locker lock(&m_autoSaveLock);
2072+ KileProject* project;
2073+ KTextEditor::Document* doc = NULL;
2074+
2075+ if(!url.isValid()) {
2076+ return;
2077+ }
2078+ project = projectFor(url);
2079+
2080+ if(!project)
2081+ return;
2082+
2083+
2084+ if(m_ki->viewManager()->currentTextView()) {
2085+ doc = m_ki->viewManager()->currentTextView()->document();
2086+ }
2087+ // we remember the actual view, so the user gets the same view back after opening
2088+
2089+ QList<KileProjectItem*> list = project->items();
2090+ for(QList<KileProjectItem*>::iterator it = list.begin(); it != list.end(); ++it) {
2091+ KileProjectItem *item = *it;
2092+
2093+ if (item->type()==KileProjectItem::ProjectFile) {
2094+ dontOpenWarning( item, i18n("Open All Project Files"), i18n("project configuration file") );
2095+ }
2096+ else if(item->type()==KileProjectItem::Image) {
2097+ dontOpenWarning( item, i18n("Open All Project Files"), i18n("graphics file") );
2098+ }
2099+ else if(!m_ki->isOpen(item->url())) {
2100+ fileOpen(item->url(), item->encoding());
2101+ }
2102+ }
2103+
2104+ if(doc) { // we have a doc so switch back to original view
2105+ m_ki->viewManager()->switchToTextView(doc->url());
2106+ }
2107+}
2108+
2109+QStringList Manager::getProjectFiles()
2110+{
2111+ QStringList filelist;
2112+
2113+ KileProject *project = activeProject();
2114+ if ( project )
2115+ {
2116+ QList<KileProjectItem*> list = project->items();
2117+ for(QList<KileProjectItem*>::iterator it = list.begin(); it != list.end(); ++it) {
2118+ KileProjectItem *item = *it;
2119+
2120+ if(item->type() != KileProjectItem::ProjectFile && item->type() != KileProjectItem::Image) {
2121+ filelist << item->url().toLocalFile();
2122+ }
2123+ }
2124+ }
2125+ return filelist;
2126+}
2127+
2128+void Manager::dontOpenWarning(KileProjectItem *item, const QString &action, const QString &filetype)
2129+{
2130+ m_ki->logWidget()->printMessage(KileTool::Info,
2131+ i18n("not opened: %1 (%2)", item->url().toLocalFile(), filetype),
2132+ action);
2133+}
2134+
2135+KileProjectItem* Manager::selectProjectFileItem(const QString &label)
2136+{
2137+ // select a project
2138+ KileProject *project = selectProject(i18n("Select Project"));
2139+ if(!project) {
2140+ return NULL;
2141+ }
2142+
2143+ // get a list of files
2144+ QStringList filelist;
2145+ QMap<QString, KileProjectItem*> map;
2146+ QList<KileProjectItem*> list = project->items();
2147+ for(QList<KileProjectItem*>::iterator it = list.begin(); it != list.end(); ++it) {
2148+ KileProjectItem *item = *it;
2149+
2150+ filelist << item->path();
2151+ map[item->path()] = item;
2152+ }
2153+
2154+ // select one of these files
2155+ KileProjectItem *item = NULL;
2156+ KileListSelector *dlg = new KileListSelector(filelist,i18n("Project Files"),label, m_ki->mainWindow());
2157+ if(dlg->exec()) {
2158+ if(dlg->currentItem() >= 0) {
2159+ QString name = filelist[dlg->currentItem()];
2160+ if(map.contains(name)) {
2161+ item = map[name];
2162+ }
2163+ else {
2164+ KMessageBox::error(m_ki->mainWindow(), i18n("Could not determine the selected file."),i18n( "Project Error"));
2165+ }
2166+ }
2167+ }
2168+ delete dlg;
2169+
2170+ return item;
2171+}
2172+
2173+QList<KileProjectItem*> Manager::selectProjectFileItems(const QString &label)
2174+{
2175+ KileProject *project = selectProject(i18n("Select Project"));
2176+ if(!project) {
2177+ return QList<KileProjectItem*>();
2178+ }
2179+
2180+ QStringList filelist;
2181+ QMap<QString,KileProjectItem *> map;
2182+
2183+ QList<KileProjectItem*> list = project->items();
2184+ for(QList<KileProjectItem*>::iterator it = list.begin(); it != list.end(); ++it) {
2185+ KileProjectItem *item = *it;
2186+
2187+ filelist << item->path();
2188+ map[item->path()] = item;
2189+ }
2190+
2191+ QList<KileProjectItem*> itemsList;
2192+
2193+ KileListSelectorMultiple *dlg = new KileListSelectorMultiple(filelist, i18n("Project Files"), label, m_ki->mainWindow());
2194+ if(dlg->exec()) {
2195+ if(dlg->currentItem() >= 0) {
2196+ QStringList selectedfiles = dlg->selected();
2197+ for(QStringList::Iterator it = selectedfiles.begin(); it != selectedfiles.end(); ++it ){
2198+ if(map.contains(*it)) {
2199+ itemsList.append(map[(*it)]);
2200+ }
2201+ else {
2202+ KMessageBox::error(m_ki->mainWindow(), i18n("Could not determine the selected file."), i18n( "Project Error"));
2203+ }
2204+ }
2205+ }
2206+ }
2207+ delete dlg;
2208+
2209+ return itemsList;
2210+}
2211+
2212+// add a new file to the project
2213+// - only when there is an active project
2214+// - if the file doesn't already belong to it (checked by addToProject)
2215+
2216+void Manager::projectAddFile(QString filename, bool graphics)
2217+{
2218+ Locker lock(&m_autoSaveLock);
2219+ KILE_DEBUG() << "===Kile::projectAddFile==============";
2220+ KileProject *project = activeProject();
2221+ if(!project) {
2222+ return;
2223+ }
2224+
2225+ QFileInfo fi(filename);
2226+ if(!fi.exists()) {
2227+ if(graphics) {
2228+ return;
2229+ }
2230+
2231+ // called from InputDialog after a \input- or \include command:
2232+ // - if the chosen file has an extension: accept
2233+ // - if not we add the default TeX extension: accept if it exists else reject
2234+ QString ext = fi.completeSuffix();
2235+ if ( ! ext.isEmpty() )
2236+ return;
2237+
2238+ filename += m_ki->extensions()->latexDocumentDefault();
2239+ if ( QFileInfo(filename).exists() )
2240+ return;
2241+ }
2242+
2243+ //ok, we have a project and an existing file
2244+ KILE_DEBUG() << "\tadd file: " << filename;
2245+ m_ki->viewManager()->updateStructure(false);
2246+
2247+ KUrl url;
2248+ url.setPath(filename);
2249+ addToProject(project, url);
2250+}
2251+
2252+const KUrl Manager::symlinkFreeURL(const KUrl& url)
2253+{
2254+#ifdef Q_WS_WIN
2255+ //TODO: maybe actually do something here? Seems unncecessary given Windows' lack of symlinks though...
2256+ //Also: the else'd code below fails badly on Windows
2257+ return url;
2258+#else
2259+ KILE_DEBUG() << "===symlinkFreeURL==";
2260+
2261+ if( !url.isLocalFile() )
2262+ return url;
2263+
2264+ QDir dir(url.directory());
2265+ QString filename=url.toLocalFile(); // if the directory does not exist we return the old url (just to be sure)
2266+
2267+ if(dir.exists())
2268+ filename= dir.canonicalPath() + '/' + url.fileName();
2269+ else
2270+ KILE_DEBUG() << "directory " << url.directory() << "does not exist";
2271+
2272+ return KUrl(filename);
2273+#endif //def Q_WS_WIN
2274+}
2275+
2276+void Manager::cleanupDocumentInfoForProjectItems(KileDocument::Info *info)
2277+{
2278+ QList<KileProjectItem*> itemsList = itemsFor(info);
2279+ for(QList<KileProjectItem*>::iterator it = itemsList.begin(); it != itemsList.end(); ++it) {
2280+ (*it)->setInfo(NULL);
2281+ }
2282+}
2283+
2284+void Manager::createProgressDialog()
2285+{
2286+ m_progressDialog = new KileWidget::ProgressDialog(m_ki->mainWindow(), i18n("Opening Project..."));
2287+ m_progressDialog->setModal(true);
2288+ m_progressDialog->setAllowCancel(false);
2289+ m_progressDialog->setLabelText(i18n("Scanning project files..."));
2290+ m_progressDialog->setAutoClose(true);
2291+ m_progressDialog->setMinimumDuration(2000);
2292+ m_progressDialog->hide();
2293+}
2294+
2295+void Manager::loadDocumentAndViewSettings(KTextEditor::Document *document)
2296+{
2297+ KConfigGroup configGroup = configGroupForDocumentSettings(document);
2298+ if(!configGroup.exists()) {
2299+ return;
2300+ }
2301+#if KDE_IS_VERSION(4,3,75)
2302+ KTextEditor::ParameterizedSessionConfigInterface *interface = qobject_cast<KTextEditor::ParameterizedSessionConfigInterface*>(document);
2303+ if(!interface) {
2304+ return;
2305+ }
2306+ interface->readParameterizedSessionConfig(configGroup, KTextEditor::ParameterizedSessionConfigInterface::SkipUrl);
2307+
2308+ QList<KTextEditor::View*> viewList = document->views();
2309+ int i = 0;
2310+ for(QList<KTextEditor::View*>::iterator it = viewList.begin(); it != viewList.end(); ++it) {
2311+ KTextEditor::View *view = *it;
2312+ KTextEditor::SessionConfigInterface *viewConfigInterface = qobject_cast<KTextEditor::SessionConfigInterface*>(view);
2313+ if(!interface) {
2314+ continue;
2315+ }
2316+ configGroup = configGroupForViewSettings(document, i);
2317+ viewConfigInterface->readSessionConfig(configGroup);
2318+ ++i;
2319+ }
2320+#endif
2321+}
2322+
2323+void Manager::saveDocumentAndViewSettings(KTextEditor::Document *document)
2324+{
2325+ KConfigGroup configGroup = configGroupForDocumentSettings(document);
2326+#if KDE_IS_VERSION(4,3,75)
2327+ KUrl url = document->url();
2328+ url.setPassword(""); // we don't want the password to appear in the configuration file
2329+ deleteDocumentAndViewSettingsGroups(url);
2330+
2331+ KTextEditor::ParameterizedSessionConfigInterface *interface = qobject_cast<KTextEditor::ParameterizedSessionConfigInterface*>(document);
2332+ if(!interface) {
2333+ return;
2334+ }
2335+ interface->writeParameterizedSessionConfig(configGroup, KTextEditor::ParameterizedSessionConfigInterface::SkipUrl);
2336+
2337+ QList<KTextEditor::View*> viewList = document->views();
2338+ int i = 0;
2339+ for(QList<KTextEditor::View*>::iterator it = viewList.begin(); it != viewList.end(); ++it) {
2340+ KTextEditor::View *view = *it;
2341+ KTextEditor::SessionConfigInterface *viewConfigInterface = qobject_cast<KTextEditor::SessionConfigInterface*>(view);
2342+ if(!interface) {
2343+ continue;
2344+ }
2345+ configGroup = configGroupForViewSettings(document, i);
2346+ viewConfigInterface->writeSessionConfig(configGroup);
2347+ ++i;
2348+ }
2349+ // finally remove the config groups for the oldest documents that exceed MAX_NUMBER_OF_STORED_SETTINGS
2350+ configGroup = KGlobal::config()->group("Session Settings");
2351+ KUrl::List urlList(configGroup.readEntry("Saved Documents", QStringList()));
2352+ urlList.removeAll(url);
2353+ urlList.push_front(url);
2354+ // remove excess elements
2355+ if(urlList.length() > MAX_NUMBER_OF_STORED_SETTINGS) {
2356+ int excessNumber = urlList.length() - MAX_NUMBER_OF_STORED_SETTINGS;
2357+ for(; excessNumber > 0; --excessNumber) {
2358+ KUrl url = urlList.takeLast();
2359+ deleteDocumentAndViewSettingsGroups(url);
2360+ }
2361+ }
2362+ configGroup.writeEntry("Documents", url);
2363+ configGroup.writeEntry("Saved Documents", urlList.toStringList());
2364+#endif
2365+}
2366+
2367+KConfigGroup Manager::configGroupForDocumentSettings(KTextEditor::Document *doc) const
2368+{
2369+ return KGlobal::config()->group(configGroupNameForDocumentSettings(doc->url()));
2370+}
2371+
2372+QString Manager::configGroupNameForDocumentSettings(const KUrl& url) const
2373+{
2374+ KUrl url2 = url;
2375+ url2.setPassword("");
2376+ return "Document-Settings,URL=" + url2.url();
2377+}
2378+
2379+KConfigGroup Manager::configGroupForViewSettings(KTextEditor::Document *doc, int viewIndex) const
2380+{
2381+ return KGlobal::config()->group(configGroupNameForViewSettings(doc->url(), viewIndex));
2382+}
2383+
2384+QString Manager::configGroupNameForViewSettings(const KUrl& url, int viewIndex) const
2385+{
2386+ KUrl url2 = url;
2387+ url2.setPassword("");
2388+ return "View-Settings,View=" + QString::number(viewIndex) + ",URL=" + url2.url();
2389+}
2390+
2391+void Manager::deleteDocumentAndViewSettingsGroups(const KUrl& url)
2392+{
2393+ QString urlString = url.url();
2394+ QStringList groupList = KGlobal::config()->groupList();
2395+ for(QStringList::iterator i = groupList.begin(); i != groupList.end(); ++i) {
2396+ QString groupName = *i;
2397+ if(groupName.startsWith("Document-Settings")
2398+ || groupName.startsWith("View-Settings")) {
2399+ int urlIndex = groupName.indexOf("URL=");
2400+ if(urlIndex >= 0 && groupName.mid(urlIndex + 4) == urlString) {
2401+ KGlobal::config()->deleteGroup(groupName);
2402+ }
2403+ }
2404+ }
2405+}
2406+
2407+}
2408+
2409+#include "kiledocmanager.moc"
2410
2411=== modified file 'debian/changelog'
2412--- debian/changelog 2012-04-16 00:46:18 +0000
2413+++ debian/changelog 2012-08-25 08:51:18 +0000
2414@@ -1,3 +1,10 @@
2415+kile (1:2.1.0-1ubuntu3) precise-updates; urgency=low
2416+
2417+ * Fixed segfault on close when a project is open (LP: #994498). Patch by
2418+ Eugene Shalygin.
2419+
2420+ -- Alessandro Menti <alessandro.menti@hotmail.it> Tue, 07 Aug 2012 19:52:40 +0200
2421+
2422 kile (1:2.1.0-1ubuntu2) precise; urgency=low
2423
2424 * Add kubuntu_use_utf8.diff to prevent pulling in texlive-latex-extra
2425
2426=== added file 'debian/patches/kile-fix-closing-994498.patch'
2427--- debian/patches/kile-fix-closing-994498.patch 1970-01-01 00:00:00 +0000
2428+++ debian/patches/kile-fix-closing-994498.patch 2012-08-25 08:51:18 +0000
2429@@ -0,0 +1,31 @@
2430+Description: Fix crash when closing with a project file open
2431+ This patch fixes a segmentation fault that occurs when Kile is closed and
2432+ a project file is open (the stack trace shows QUrl::isEmpty at the top of
2433+ the stack in one of the threads). The original "iterator" is removed and
2434+ replaced by a more reliable access to the m_projects collection.
2435+ Upstream patch by Eugene Shalygin.
2436+Author: Alessandro Menti <alessandro.menti@hotmail.it>
2437+Bug-Ubuntu: https://bugs.launchpad.net/bugs/994498
2438+Origin: upstream, https://bugs.kde.org/attachment.cgi?id=66957
2439+Bug: https://bugs.kde.org/show_bug.cgi?id=289458
2440+Forwarded: not-needed
2441+
2442+--- kile-2.1.0.orig/src/kiledocmanager.cpp
2443++++ kile-2.1.0/src/kiledocmanager.cpp
2444+@@ -1738,11 +1738,11 @@ bool Manager::projectCloseAll()
2445+ Locker lock(&m_autoSaveLock);
2446+ KILE_DEBUG() << "==Kile::projectCloseAll==========================";
2447+
2448+- for(QList<KileProject*>::iterator it = m_projects.begin(); it != m_projects.end(); ++it) {
2449+- if(!projectClose((*it)->url())) {
2450+- return false;
2451+- }
2452+- }
2453++ while (m_projects.size()) {
2454++ if(!projectClose(m_projects.front()->url())) {
2455++ return false;
2456++ }
2457++ }
2458+
2459+ return true;
2460+ }
2461
2462=== modified file 'debian/patches/series'
2463--- debian/patches/series 2012-04-16 00:46:18 +0000
2464+++ debian/patches/series 2012-08-25 08:51:18 +0000
2465@@ -3,3 +3,4 @@
2466 kubuntu_01_improved_viewpart_warning.diff
2467 kubuntu_02_disable_embedded_kbibtex.diff
2468 kubuntu_use_utf8.diff
2469+kile-fix-closing-994498.patch
2470
2471=== modified file 'src/kiledocmanager.cpp'
2472--- src/kiledocmanager.cpp 2011-06-11 14:55:19 +0000
2473+++ src/kiledocmanager.cpp 2012-08-25 08:51:18 +0000
2474@@ -1738,11 +1738,11 @@
2475 Locker lock(&m_autoSaveLock);
2476 KILE_DEBUG() << "==Kile::projectCloseAll==========================";
2477
2478- for(QList<KileProject*>::iterator it = m_projects.begin(); it != m_projects.end(); ++it) {
2479- if(!projectClose((*it)->url())) {
2480- return false;
2481- }
2482- }
2483+ while (m_projects.size()) {
2484+ if(!projectClose(m_projects.front()->url())) {
2485+ return false;
2486+ }
2487+ }
2488
2489 return true;
2490 }

Subscribers

People subscribed via source and target branches