OSDN Git Service

ac0491c0a2a673241e5f8bf3ea2580f77168e86e
[qt-creator-jp/qt-creator-jp.git] / src / plugins / bookmarks / bookmarkmanager.cpp
1 /**************************************************************************
2 **
3 ** This file is part of Qt Creator
4 **
5 ** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
6 **
7 ** Contact: Nokia Corporation (qt-info@nokia.com)
8 **
9 ** No Commercial Usage
10 **
11 ** This file contains pre-release code and may not be distributed.
12 ** You may use this file in accordance with the terms and conditions
13 ** contained in the Technology Preview License Agreement accompanying
14 ** this package.
15 **
16 ** GNU Lesser General Public License Usage
17 **
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file.  Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 **
25 ** In addition, as a special exception, Nokia gives you certain additional
26 ** rights.  These rights are described in the Nokia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 **
29 ** If you have questions regarding the use of this file, please contact
30 ** Nokia at qt-info@nokia.com.
31 **
32 **************************************************************************/
33
34 #include "bookmarkmanager.h"
35
36 #include "bookmark.h"
37 #include "bookmarksplugin.h"
38 #include "bookmarks_global.h"
39
40 #include <coreplugin/editormanager/editormanager.h>
41 #include <coreplugin/icore.h>
42 #include <coreplugin/actionmanager/actionmanager.h>
43 #include <projectexplorer/projectexplorer.h>
44 #include <projectexplorer/session.h>
45 #include <texteditor/basetexteditor.h>
46 #include <utils/qtcassert.h>
47
48 #include <QtCore/QDebug>
49 #include <QtCore/QFileInfo>
50
51 #include <QtGui/QAction>
52 #include <QtGui/QContextMenuEvent>
53 #include <QtGui/QMenu>
54 #include <QtGui/QPainter>
55
56 Q_DECLARE_METATYPE(Bookmarks::Internal::Bookmark*)
57
58 using namespace Bookmarks;
59 using namespace Bookmarks::Internal;
60 using namespace ProjectExplorer;
61 using namespace Core;
62
63 BookmarkDelegate::BookmarkDelegate(QObject *parent)
64     : QStyledItemDelegate(parent), m_normalPixmap(0), m_selectedPixmap(0)
65 {
66 }
67
68 BookmarkDelegate::~BookmarkDelegate()
69 {
70     delete m_normalPixmap;
71     delete m_selectedPixmap;
72 }
73
74 QSize BookmarkDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const
75 {
76     QStyleOptionViewItemV4 opt = option;
77     initStyleOption(&opt, index);
78
79     QFontMetrics fm(option.font);
80     QSize s;
81     s.setWidth(option.rect.width());
82     s.setHeight(fm.height() * 2 + 10);
83     return s;
84 }
85
86 void BookmarkDelegate::generateGradientPixmap(int width, int height, QColor color, bool selected) const
87 {
88
89     QColor c = color;
90     c.setAlpha(0);
91
92     QPixmap *pixmap = new QPixmap(width+1, height);
93     pixmap->fill(c);
94
95     QPainter painter(pixmap);
96     painter.setPen(Qt::NoPen);
97
98     QLinearGradient lg;
99     lg.setCoordinateMode(QGradient::ObjectBoundingMode);
100     lg.setFinalStop(1,0);
101
102     lg.setColorAt(0, c);
103     lg.setColorAt(0.4, color);
104
105         painter.setBrush(lg);
106     painter.drawRect(0, 0, width+1, height);
107
108     if (selected)
109         m_selectedPixmap = pixmap;
110     else
111         m_normalPixmap = pixmap;
112 }
113
114 void BookmarkDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
115 {
116     QStyleOptionViewItemV4 opt = option;
117     initStyleOption(&opt, index);
118     painter->save();
119
120     QFontMetrics fm(opt.font);
121     static int lwidth = fm.width("8888") + 18;
122
123     QColor backgroundColor;
124     QColor textColor;
125
126     bool selected = opt.state & QStyle::State_Selected;
127
128     if (selected) {
129         painter->setBrush(opt.palette.highlight().color());
130         backgroundColor = opt.palette.highlight().color();
131         if (!m_selectedPixmap)
132             generateGradientPixmap(lwidth, fm.height()+1, backgroundColor, selected);
133     } else {
134         painter->setBrush(opt.palette.background().color());
135         backgroundColor = opt.palette.background().color();
136         if (!m_normalPixmap)
137             generateGradientPixmap(lwidth, fm.height(), backgroundColor, selected);
138     }
139     painter->setPen(Qt::NoPen);
140     painter->drawRect(opt.rect);
141
142     // Set Text Color
143     if (opt.state & QStyle::State_Selected)
144         textColor = opt.palette.highlightedText().color();
145     else
146         textColor = opt.palette.text().color();
147
148     painter->setPen(textColor);
149
150
151     // TopLeft
152     QString topLeft = index.data(BookmarkManager::Filename ).toString();
153     painter->drawText(6, 2 + opt.rect.top() + fm.ascent(), topLeft);
154
155     QString topRight = index.data(BookmarkManager::LineNumber).toString();
156     // Check whether we need to be fancy and paint some background
157     int fwidth = fm.width(topLeft);
158     if (fwidth + lwidth > opt.rect.width()) {
159         int left = opt.rect.right() - lwidth;
160         painter->drawPixmap(left, opt.rect.top(), selected? *m_selectedPixmap : *m_normalPixmap);
161     }
162     // topRight
163     painter->drawText(opt.rect.right() - fm.width(topRight) - 6 , 2 + opt.rect.top() + fm.ascent(), topRight);
164
165     // Directory
166     QColor mix;
167     mix.setRgbF(0.7 * textColor.redF()   + 0.3 * backgroundColor.redF(),
168                 0.7 * textColor.greenF() + 0.3 * backgroundColor.greenF(),
169                 0.7 * textColor.blueF()  + 0.3 * backgroundColor.blueF());
170     painter->setPen(mix);
171 //
172 //    QString directory = index.data(BookmarkManager::Directory).toString();
173 //    int availableSpace = opt.rect.width() - 12;
174 //    if (fm.width(directory) > availableSpace) {
175 //        // We need a shorter directory
176 //        availableSpace -= fm.width("...");
177 //
178 //        int pos = directory.size();
179 //        int idx;
180 //        forever {
181 //            idx = directory.lastIndexOf("/", pos-1);
182 //            if (idx == -1) {
183 //                // Can't happen, this means the string did fit after all?
184 //                break;
185 //            }
186 //            int width = fm.width(directory.mid(idx, pos-idx));
187 //            if (width > availableSpace) {
188 //                directory = "..." + directory.mid(pos);
189 //                break;
190 //            } else {
191 //                pos = idx;
192 //                availableSpace -= width;
193 //            }
194 //        }
195 //    }
196 //
197 //    painter->drawText(3, opt.rect.top() + fm.ascent() + fm.height() + 6, directory);
198
199     QString lineText = index.data(BookmarkManager::LineText).toString().trimmed();
200     painter->drawText(6, opt.rect.top() + fm.ascent() + fm.height() + 6, lineText);
201
202     // Separator lines
203     painter->setPen(QColor::fromRgb(150,150,150));
204     painter->drawLine(0, opt.rect.bottom(), opt.rect.right(), opt.rect.bottom());
205     painter->restore();
206 }
207
208 BookmarkView::BookmarkView(QWidget *parent)  :
209     QListView(parent),
210     m_bookmarkContext(new BookmarkContext(this)),
211     m_manager(0)
212 {
213     setWindowTitle(tr("Bookmarks"));
214
215     connect(this, SIGNAL(clicked(const QModelIndex &)),
216             this, SLOT(gotoBookmark(const QModelIndex &)));
217
218     ICore::instance()->addContextObject(m_bookmarkContext);
219
220     setItemDelegate(new BookmarkDelegate(this));
221     setFrameStyle(QFrame::NoFrame);
222     setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
223     setFocusPolicy(Qt::NoFocus);
224 }
225
226 BookmarkView::~BookmarkView()
227 {
228     ICore::instance()->removeContextObject(m_bookmarkContext);
229 }
230
231 void BookmarkView::contextMenuEvent(QContextMenuEvent *event)
232 {
233     QMenu menu;
234     QAction *moveUp = menu.addAction(tr("Move Up"));
235     QAction *moveDown = menu.addAction(tr("Move Down"));
236     QAction *remove = menu.addAction(tr("&Remove"));
237     QAction *removeAll = menu.addAction(tr("Remove All"));
238     m_contextMenuIndex = indexAt(event->pos());
239     if (!m_contextMenuIndex.isValid()) {
240         moveUp->setEnabled(false);
241         moveDown->setEnabled(false);
242         remove->setEnabled(false);
243     }
244
245     if (model()->rowCount() == 0)
246         removeAll->setEnabled(false);
247
248     connect(moveUp, SIGNAL(triggered()),
249             m_manager, SLOT(moveUp()));
250     connect(moveDown, SIGNAL(triggered()),
251             m_manager, SLOT(moveDown()));
252     connect(remove, SIGNAL(triggered()),
253             this, SLOT(removeFromContextMenu()));
254     connect(removeAll, SIGNAL(triggered()),
255             this, SLOT(removeAll()));
256
257     menu.exec(mapToGlobal(event->pos()));
258 }
259
260 void BookmarkView::removeFromContextMenu()
261 {
262     removeBookmark(m_contextMenuIndex);
263 }
264
265 void BookmarkView::removeBookmark(const QModelIndex& index)
266 {
267     Bookmark *bm = m_manager->bookmarkForIndex(index);
268     m_manager->removeBookmark(bm);
269 }
270
271 // The perforcemance of this function could be greatly improved.
272 //
273 void BookmarkView::removeAll()
274 {
275     while (m_manager->rowCount()) {
276         QModelIndex index = m_manager->index(0, 0);
277         removeBookmark(index);
278     }
279 }
280
281 void BookmarkView::setModel(QAbstractItemModel *model)
282 {
283     BookmarkManager *manager = qobject_cast<BookmarkManager *>(model);
284     QTC_ASSERT(manager, return);
285     m_manager = manager;
286     QListView::setModel(model);
287     setSelectionModel(manager->selectionModel());
288     setSelectionMode(QAbstractItemView::SingleSelection);
289     setSelectionBehavior(QAbstractItemView::SelectRows);
290 }
291
292 void BookmarkView::gotoBookmark(const QModelIndex &index)
293 {
294     Bookmark *bk = m_manager->bookmarkForIndex(index);
295     if (!m_manager->gotoBookmark(bk))
296         m_manager->removeBookmark(bk);
297 }
298
299 ////
300 // BookmarkContext
301 ////
302
303 BookmarkContext::BookmarkContext(BookmarkView *widget)
304     : Core::IContext(widget),
305       m_bookmarkView(widget),
306       m_context(Constants::BOOKMARKS_CONTEXT)
307 {
308 }
309
310 Context BookmarkContext::context() const
311 {
312     return m_context;
313 }
314
315 QWidget *BookmarkContext::widget()
316 {
317     return m_bookmarkView;
318 }
319
320 ////
321 // BookmarkManager
322 ////
323
324 BookmarkManager::BookmarkManager() :
325     m_bookmarkIcon(QLatin1String(":/bookmarks/images/bookmark.png")),
326     m_selectionModel(new QItemSelectionModel(this, this))
327 {
328     connect(Core::ICore::instance(), SIGNAL(contextChanged(Core::IContext*,Core::Context)),
329             this, SLOT(updateActionStatus()));
330
331     connect(ProjectExplorerPlugin::instance()->session(), SIGNAL(sessionLoaded()),
332             this, SLOT(loadBookmarks()));
333
334     updateActionStatus();
335 }
336
337 BookmarkManager::~BookmarkManager()
338 {
339     DirectoryFileBookmarksMap::iterator it, end;
340     end = m_bookmarksMap.end();
341     for (it = m_bookmarksMap.begin(); it != end; ++it) {
342         FileNameBookmarksMap *bookmarks = it.value();
343         qDeleteAll(*bookmarks);
344         delete bookmarks;
345     }
346 }
347
348 QItemSelectionModel *BookmarkManager::selectionModel() const
349 {
350     return m_selectionModel;
351 }
352
353 QModelIndex BookmarkManager::index(int row, int column, const QModelIndex &parent) const
354 {
355     if (parent.isValid())
356         return QModelIndex();
357     else
358         return createIndex(row, column, 0);
359 }
360
361 QModelIndex BookmarkManager::parent(const QModelIndex &) const
362 {
363     return QModelIndex();
364 }
365
366 int BookmarkManager::rowCount(const QModelIndex &parent) const
367 {
368     if (parent.isValid())
369         return 0;
370     else
371         return m_bookmarksList.count();
372 }
373
374 int BookmarkManager::columnCount(const QModelIndex &parent) const
375 {
376     if (parent.isValid())
377         return 0;
378     return 3;
379 }
380
381 QVariant BookmarkManager::data(const QModelIndex &index, int role) const
382 {
383     if (!index.isValid() || index.column() !=0 || index.row() < 0 || index.row() >= m_bookmarksList.count())
384         return QVariant();
385
386     if (role == BookmarkManager::Filename)
387         return m_bookmarksList.at(index.row())->fileName();
388     else if (role == BookmarkManager::LineNumber)
389         return m_bookmarksList.at(index.row())->lineNumber();
390     else if (role == BookmarkManager::Directory)
391         return m_bookmarksList.at(index.row())->path();
392     else if (role == BookmarkManager::LineText)
393         return m_bookmarksList.at(index.row())->lineText();
394     else if (role == Qt::ToolTipRole)
395         return m_bookmarksList.at(index.row())->filePath();
396
397     return QVariant();
398 }
399
400 void BookmarkManager::toggleBookmark()
401 {
402     TextEditor::ITextEditor *editor = currentTextEditor();
403     if (!editor)
404         return;
405
406     toggleBookmark(editor->file()->fileName(), editor->currentLine());
407 }
408
409 void BookmarkManager::toggleBookmark(const QString &fileName, int lineNumber)
410 {
411     const QFileInfo fi(fileName);
412     const int editorLine = lineNumber;
413
414     // Remove any existing bookmark on this line
415     if (Bookmark *mark = findBookmark(fi.path(), fi.fileName(), lineNumber)) {
416         // TODO check if the bookmark is really on the same markable Interface
417         removeBookmark(mark);
418         return;
419     }
420
421     // Add a new bookmark if no bookmark existed on this line
422     Bookmark *bookmark = new Bookmark(fi.filePath(), editorLine, this);
423     addBookmark(bookmark);
424 }
425
426 void BookmarkManager::updateBookmark(Bookmark *bookmark)
427 {
428     int idx = m_bookmarksList.indexOf(bookmark);
429     emit dataChanged(index(idx, 0, QModelIndex()), index(idx, 2, QModelIndex()));
430     saveBookmarks();
431 }
432
433 void BookmarkManager::removeAllBookmarks()
434 {
435     if (m_bookmarksList.isEmpty())
436         return;
437     beginRemoveRows(QModelIndex(), 0, m_bookmarksList.size() - 1);
438
439     DirectoryFileBookmarksMap::const_iterator it, end;
440     end = m_bookmarksMap.constEnd();
441     for (it = m_bookmarksMap.constBegin(); it != end; ++it) {
442         FileNameBookmarksMap *files = it.value();
443         FileNameBookmarksMap::const_iterator jt, jend;
444         jend = files->constEnd();
445         for (jt = files->constBegin(); jt != jend; ++jt) {
446             delete jt.value();
447         }
448         files->clear();
449         delete files;
450     }
451     m_bookmarksMap.clear();
452     m_bookmarksList.clear();
453     endRemoveRows();
454 }
455
456 void BookmarkManager::removeBookmark(Bookmark *bookmark)
457 {
458     int idx = m_bookmarksList.indexOf(bookmark);
459     beginRemoveRows(QModelIndex(), idx, idx);
460
461     const QFileInfo fi(bookmark->filePath() );
462     FileNameBookmarksMap *files = m_bookmarksMap.value(fi.path());
463
464     FileNameBookmarksMap::iterator i = files->begin();
465     while (i != files->end()) {
466         if (i.value() == bookmark) {
467             files->erase(i);
468             delete bookmark;
469             break;
470         }
471         ++i;
472     }
473     if (files->count() <= 0) {
474         m_bookmarksMap.remove(fi.path());
475         delete files;
476     }
477
478
479     m_bookmarksList.removeAt(idx);
480     endRemoveRows();
481
482     if (selectionModel()->currentIndex().isValid())
483         selectionModel()->setCurrentIndex(selectionModel()->currentIndex(), QItemSelectionModel::Select | QItemSelectionModel::Clear);
484
485     updateActionStatus();
486     saveBookmarks();
487 }
488
489 Bookmark *BookmarkManager::bookmarkForIndex(QModelIndex index)
490 {
491     if (!index.isValid() || index.row() >= m_bookmarksList.size())
492         return 0;
493     return m_bookmarksList.at(index.row());
494 }
495
496
497 bool BookmarkManager::gotoBookmark(Bookmark* bookmark)
498 {
499     using namespace TextEditor;
500     if (ITextEditor *editor = BaseTextEditorWidget::openEditorAt(bookmark->filePath(), bookmark->lineNumber()))
501         return (editor->currentLine() == bookmark->lineNumber());
502     return false;
503 }
504
505 void BookmarkManager::nextInDocument()
506 {
507     documentPrevNext(true);
508 }
509
510 void BookmarkManager::prevInDocument()
511 {
512     documentPrevNext(false);
513 }
514
515 void BookmarkManager::documentPrevNext(bool next)
516 {
517     TextEditor::ITextEditor *editor = currentTextEditor();
518     int editorLine = editor->currentLine();
519     QFileInfo fi(editor->file()->fileName());
520     if (!m_bookmarksMap.contains(fi.path()))
521         return;
522
523     int firstLine = -1;
524     int lastLine = -1;
525     int prevLine = -1;
526     int nextLine = -1;
527     const QList<Bookmark*> marks = m_bookmarksMap.value(fi.path())->values(fi.fileName());
528     for (int i = 0; i < marks.count(); ++i) {
529         int markLine = marks.at(i)->lineNumber();
530         if (firstLine == -1 || firstLine > markLine)
531             firstLine = markLine;
532         if (lastLine < markLine)
533             lastLine = markLine;
534         if (markLine < editorLine && prevLine < markLine)
535             prevLine = markLine;
536         if (markLine > editorLine &&
537             (nextLine == -1 || nextLine > markLine))
538             nextLine = markLine;
539     }
540
541     Core::EditorManager *em = Core::EditorManager::instance();
542     em->addCurrentPositionToNavigationHistory();
543     if (next) {
544         if (nextLine == -1)
545             editor->gotoLine(firstLine);
546         else
547             editor->gotoLine(nextLine);
548     } else {
549         if (prevLine == -1)
550             editor->gotoLine(lastLine);
551         else
552             editor->gotoLine(prevLine);
553     }
554 }
555
556 void BookmarkManager::next()
557 {
558     QModelIndex current = selectionModel()->currentIndex();
559     if (!current.isValid())
560         return;
561     int row = current.row();
562     ++row;
563     while (true) {
564         if (row == m_bookmarksList.size())
565             row = 0;
566
567         Bookmark *bk = m_bookmarksList.at(row);
568         if (gotoBookmark(bk)) {
569             QModelIndex newIndex = current.sibling(row, current.column());
570             selectionModel()->setCurrentIndex(newIndex, QItemSelectionModel::Select | QItemSelectionModel::Clear);
571             return;
572         }
573         removeBookmark(bk);
574         if (m_bookmarksList.isEmpty()) // No bookmarks anymore ...
575             return;
576     }
577 }
578
579 void BookmarkManager::prev()
580 {
581     QModelIndex current = selectionModel()->currentIndex();
582     if (!current.isValid())
583         return;
584
585     int row = current.row();
586     while (true) {
587         if (row == 0)
588             row = m_bookmarksList.size();
589         --row;
590         Bookmark *bk = m_bookmarksList.at(row);
591         if (gotoBookmark(bk)) {
592             QModelIndex newIndex = current.sibling(row, current.column());
593             selectionModel()->setCurrentIndex(newIndex, QItemSelectionModel::Select | QItemSelectionModel::Clear);
594             return;
595         }
596         removeBookmark(bk);
597         if (m_bookmarksList.isEmpty())
598             return;
599     }
600 }
601
602 TextEditor::ITextEditor *BookmarkManager::currentTextEditor() const
603 {
604     Core::EditorManager *em = Core::EditorManager::instance();
605     Core::IEditor *currEditor = em->currentEditor();
606     if (!currEditor)
607         return 0;
608     return qobject_cast<TextEditor::ITextEditor *>(currEditor);
609 }
610
611 /* Returns the current session. */
612 SessionManager *BookmarkManager::sessionManager() const
613 {
614     return ProjectExplorerPlugin::instance()->session();
615 }
616
617 BookmarkManager::State BookmarkManager::state() const
618 {
619     if (m_bookmarksMap.empty())
620         return NoBookMarks;
621
622     TextEditor::ITextEditor *editor = currentTextEditor();
623     if (!editor)
624         return HasBookMarks;
625
626     const QFileInfo fi(editor->file()->fileName());
627
628     const DirectoryFileBookmarksMap::const_iterator dit = m_bookmarksMap.constFind(fi.path());
629     if (dit == m_bookmarksMap.constEnd())
630         return HasBookMarks;
631
632     return HasBookmarksInDocument;
633 }
634
635 void BookmarkManager::updateActionStatus()
636 {
637     emit updateActions(state());
638 }
639
640 void BookmarkManager::moveUp()
641 {
642     QModelIndex current = selectionModel()->currentIndex();
643     int row = current.row();
644     if (row == 0)
645         row = m_bookmarksList.size();
646      --row;
647
648     // swap current.row() and row
649
650     Bookmark *b = m_bookmarksList.at(row);
651     m_bookmarksList[row] = m_bookmarksList.at(current.row());
652     m_bookmarksList[current.row()] = b;
653
654     QModelIndex topLeft = current.sibling(row, 0);
655     QModelIndex bottomRight = current.sibling(current.row(), 2);
656     emit dataChanged(topLeft, bottomRight);
657     selectionModel()->setCurrentIndex(current.sibling(row, 0), QItemSelectionModel::Select | QItemSelectionModel::Clear);
658 }
659
660 void BookmarkManager::moveDown()
661 {
662     QModelIndex current = selectionModel()->currentIndex();
663     int row = current.row();
664     ++row;
665     if (row == m_bookmarksList.size())
666         row = 0;
667
668     // swap current.row() and row
669     Bookmark *b = m_bookmarksList.at(row);
670     m_bookmarksList[row] = m_bookmarksList.at(current.row());
671     m_bookmarksList[current.row()] = b;
672
673     QModelIndex topLeft = current.sibling(current.row(), 0);
674     QModelIndex bottomRight = current.sibling(row, 2);
675     emit dataChanged(topLeft, bottomRight);
676     selectionModel()->setCurrentIndex(current.sibling(row, 0), QItemSelectionModel::Select | QItemSelectionModel::Clear);
677 }
678
679 /* Returns the bookmark at the given file and line number, or 0 if no such bookmark exists. */
680 Bookmark* BookmarkManager::findBookmark(const QString &path, const QString &fileName, int lineNumber)
681 {
682     if (m_bookmarksMap.contains(path)) {
683         foreach (Bookmark *bookmark, m_bookmarksMap.value(path)->values(fileName)) {
684             if (bookmark->lineNumber() == lineNumber)
685                 return bookmark;
686         }
687     }
688     return 0;
689 }
690
691 /* Adds a bookmark to the internal data structures. The 'userset' parameter
692  * determines whether action status should be updated and whether the bookmarks
693  * should be saved to the session settings.
694  */
695 void BookmarkManager::addBookmark(Bookmark *bookmark, bool userset)
696 {
697     beginInsertRows(QModelIndex(), m_bookmarksList.size(), m_bookmarksList.size());
698     const QFileInfo fi(bookmark->filePath());
699     const QString &path = fi.path();
700
701     if (!m_bookmarksMap.contains(path))
702         m_bookmarksMap.insert(path, new FileNameBookmarksMap());
703     m_bookmarksMap.value(path)->insert(fi.fileName(), bookmark);
704
705     m_bookmarksList.append(bookmark);
706
707     endInsertRows();
708     if (userset) {
709         updateActionStatus();
710         saveBookmarks();
711     }
712     selectionModel()->setCurrentIndex(index(m_bookmarksList.size()-1 , 0, QModelIndex()), QItemSelectionModel::Select | QItemSelectionModel::Clear);
713 }
714
715 /* Adds a new bookmark based on information parsed from the string. */
716 void BookmarkManager::addBookmark(const QString &s)
717 {
718     int index2 = s.lastIndexOf(':');
719     int index1 = s.indexOf(':');
720     if (index2 != -1 || index1 != -1) {
721         const QString &filePath = s.mid(index1+1, index2-index1-1);
722         const int lineNumber = s.mid(index2 + 1).toInt();
723         const QFileInfo fi(filePath);
724
725         if (!filePath.isEmpty() && !findBookmark(fi.path(), fi.fileName(), lineNumber)) {
726             Bookmark *b = new Bookmark(filePath, lineNumber, this);
727             addBookmark(b, false);
728         }
729     } else {
730         qDebug() << "BookmarkManager::addBookmark() Invalid bookmark string:" << s;
731     }
732 }
733
734 /* Puts the bookmark in a string for storing it in the settings. */
735 QString BookmarkManager::bookmarkToString(const Bookmark *b)
736 {
737     const QLatin1Char colon(':');
738     // Empty string was the name of the bookmark, which now is always ""
739     return QLatin1String("") + colon + b->filePath() + colon + QString::number(b->lineNumber());
740 }
741
742 /* Saves the bookmarks to the session settings. */
743 void BookmarkManager::saveBookmarks()
744 {
745     SessionManager *s = sessionManager();
746     if (!s)
747         return;
748
749     QStringList list;
750     foreach (const FileNameBookmarksMap *bookmarksMap, m_bookmarksMap)
751         foreach (const Bookmark *bookmark, *bookmarksMap)
752             list << bookmarkToString(bookmark);
753
754     s->setValue("Bookmarks", list);
755 }
756
757 /* Loads the bookmarks from the session settings. */
758 void BookmarkManager::loadBookmarks()
759 {
760     removeAllBookmarks();
761     SessionManager *s = sessionManager();
762     if (!s)
763         return;
764
765     const QStringList &list = s->value("Bookmarks").toStringList();
766     foreach (const QString &bookmarkString, list)
767         addBookmark(bookmarkString);
768
769     updateActionStatus();
770 }
771
772 // BookmarkViewFactory
773
774 BookmarkViewFactory::BookmarkViewFactory(BookmarkManager *bm)
775     : m_manager(bm)
776 {
777
778 }
779
780 QString BookmarkViewFactory::displayName() const
781 {
782     return BookmarkView::tr("Bookmarks");
783 }
784
785 int BookmarkViewFactory::priority() const
786 {
787     return 300;
788 }
789
790 QString BookmarkViewFactory::id() const
791 {
792     return QLatin1String("Bookmarks");
793 }
794
795 QKeySequence BookmarkViewFactory::activationSequence() const
796 {
797     return QKeySequence(Qt::ALT + Qt::Key_M);
798 }
799
800 Core::NavigationView BookmarkViewFactory::createWidget()
801 {
802     BookmarkView *bookmarkView = new BookmarkView();
803     bookmarkView->setModel(m_manager);
804     Core::NavigationView view;
805     view.widget = bookmarkView;
806     return view;
807 }