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

Subscribers

People subscribed via source and target branches