[gnote] Add Table Of Content add-in
- From: Aurimas Černius <aurimasc src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnote] Add Table Of Content add-in
- Date: Sat, 27 Apr 2013 16:23:48 +0000 (UTC)
commit b0178747f9a1926cb23f25099c03da107c1565d5
Author: Aurimas Černius <aurisc4 gmail com>
Date: Sat Apr 27 19:06:17 2013 +0300
Add Table Of Content add-in
Bug 698059.
Thanks Luc Pionchon.
configure.ac | 1 +
help/C/gnote-addin-tableofcontent.page | 187 ++++++++++
help/Makefile.am | 1 +
po/POTFILES.in | 2 +
src/addins/Makefile.am | 1 +
src/addins/tableofcontent/Makefile.am | 23 ++
src/addins/tableofcontent/NEWS | 60 ++++
src/addins/tableofcontent/TODO | 108 ++++++
.../tableofcontent/tableofcontent.desktop.in | 10 +
src/addins/tableofcontent/tableofcontent.hpp | 47 +++
.../tableofcontent/tableofcontentmenuitem.cpp | 88 +++++
.../tableofcontent/tableofcontentmenuitem.hpp | 56 +++
.../tableofcontent/tableofcontentnoteaddin.cpp | 368 ++++++++++++++++++++
.../tableofcontent/tableofcontentnoteaddin.hpp | 95 +++++
14 files changed, 1047 insertions(+), 0 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index 6c47960..72ca3eb 100644
--- a/configure.ac
+++ b/configure.ac
@@ -169,6 +169,7 @@ src/addins/printnotes/Makefile
src/addins/replacetitle/Makefile
src/addins/statistics/Makefile
src/addins/stickynoteimport/Makefile
+src/addins/tableofcontent/Makefile
src/addins/tomboyimport/Makefile
src/addins/underline/Makefile
src/addins/webdavsyncservice/Makefile
diff --git a/help/C/gnote-addin-tableofcontent.page b/help/C/gnote-addin-tableofcontent.page
new file mode 100644
index 0000000..81fa12d
--- /dev/null
+++ b/help/C/gnote-addin-tableofcontent.page
@@ -0,0 +1,187 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ "Table of Content" is a Note add-in for Gnote.
+ It lists Note's table of content in a menu.
+
+ Copyright (c) 2013 Luc Pionchon <pionchon luc gmail com>
+
+ Permission is granted to copy, distribute and/or modify this document
+ under the terms of the GNU Free Documentation License, Version 1.1
+ or any later version published by the Free Software Foundation;
+ with no Invariant Sections, with no Front-Cover Texts, and with no
+ Back-Cover Texts.
+ FIXME: is this true? (no invariant, no front, no back?)
+ FIXME: does the statement have to show in the rendered document?
+
+ A copy of the license is included in the section entitled "GNU
+ Free Documentation License".
+ FIXME: is this true? Is there a (GNOME? Yelp?) common GFDL topic?
+-->
+<page xmlns="http://projectmallard.org/1.0/"
+ type="topic"
+ id="addin-tableofcontent">
+
+ <info>
+ <revision
+ status="candidate"
+ pkgversion="gnote-addin-tableofcontent-version-0.9"
+ />
+ <!-- Status:
+ stub contains little to no real content
+ incomplete outline of all information, but lacking content
+ draft all content available, but unpolished
+ review ready to be reviewed by editors
+ candidate reviewed and awaiting a final approval
+ final approved and ready for publication or distribution
+ outdated was once complete or nearly complete, but needs to be revised to reflect changes
+
+ Other possible attributes:
+ version="" revision version
+ docversion="" enclosing document
+ date="2011-03-08" revision date
+ -->
+ <license href="http://www.gnu.org/licenses/fdl-1.1.html"><p>
+ This <em>help topic</em> is licensied under the
+ <link href="http://www.gnu.org/licenses/fdl-1.1.html">
+ GNU Free Documentation License, Version 1.1</link> (GFDL).
+ It means that you are free to copy, distribute and/or modify this document, under some conditions.
+ </p>
+ </license>
+
+ <credit type="author copyright">
+ <name>Luc Pionchon</name><email>pionchon luc gmail com</email><years>2013</years></credit>
+ <!-- Credit type: (can have several types)
+ author somebody responsible for writing content
+ editor somebody who has provided reviews or editorial corrections
+ copyright a person or entity which holds copyright on the work
+ maintainer the person or entity currently responsible for the work
+ collaborator somebody who has provided extensive rough information
+ translator somebody who has translated the work into another language
+ publisher a person or entity who distributes formatted copies
+
+ <credit> can have a URL, for example for a publisher, using FOAF namespace:
+ <page xmlns="http://xmlns.com/foaf/0.1/">http://flossmanuals.net/</page>
+ -->
+
+ <link type="guide" xref="index#advanced"/>
+ <link type="topic" xref="addins-preferences"/>
+ <link type="topic" xref="editing-notes"/>
+ <link type="topic" xref="searching-notes"/>
+ <desc>Navigate long structured notes</desc>
+ </info>
+
+
+<title>Note's Table of Content</title>
+
+<desc><em>Navigate long structured notes</em></desc>
+
+<note><p>
+ This is an add-in to <app>Gnotes</app>.
+ When this add-in is installed,
+ there is a <gui>Table of Content</gui> entry in the <gui>Tools</gui> menu.
+ See <link xref="addins-preferences"/> to know how to activate an add-in.
+</p></note>
+
+
+<section id="nuttshell"><title>In a nutshell</title>
+
+<list type="numbered">
+ <item>
+ <p>a header is a full line of text, formatted with <gui>Bold+Huge</gui> or <gui>Bold+Large</gui></p>
+ </item>
+ <item>
+ <p>select a full line and set it has a header with
+ <keyseq><key>Ctrl</key><key>1</key></keyseq> or <keyseq><key>Ctrl</key><key>2</key></keyseq>
+ </p>
+ </item>
+ <item>
+ <p>open the table of content with <keyseq><key>Ctrl</key><key>Alt</key><key>1</key></keyseq></p>
+ </item>
+</list>
+
+</section>
+
+
+<section id="navigating"><title>Navigating through long notes</title>
+
+<p>
+When writting a long note, it may become difficult to navigate through.
+It is then natural to structure the note by marking sections and subsections with headers.
+</p>
+
+<p>
+This add-in makes it easy to navigate through long structured notes.
+Once you have set headers in your note, the table of content of the note will show in a menu.
+Then you can jump directly from the menu to the selected header.
+</p>
+
+</section>
+
+
+<section id="setheaders"><title>Structuring your notes with headers</title>
+
+<p>
+A header is simply a complete line with a specific text formatting:
+</p>
+<list>
+ <item><p>headers of level 1, for sections, are lines formatted with a <gui>Bold+Huge</gui> font</p></item>
+ <item><p>headers of level 2, for subsections, are lines formatted with a <gui>Bold+Large</gui>
font</p></item>
+</list>
+
+
+<p>To format a header line, first select a full line of text, then either:</p>
+
+<list>
+ <item>
+ <p>use the commands <gui>Level 1 Header</gui> and <gui>Level 2 Header</gui>,
+ in the <guiseq><gui>Tools</gui><gui>Table of Content</gui></guiseq> menu</p>
+ </item>
+
+ <item>
+ <p>use the keyboard shortcuts <keyseq><key>Ctrl</key><key>1</key></keyseq> for headers of level 1,
+ and <keyseq><key>Ctrl</key><key>2</key></keyseq> for headers of level 2</p>
+ </item>
+</list>
+
+<p>Alternatively, on a new line, activate the command and then enter the header title.</p>
+
+<p>You can actually even use the normal formatting commands from the <gui>Text</gui> menu:
+ <gui>Bold</gui>, <gui>Large</gui> and <gui>Huge</gui>, and their respective keyboard shortcuts.
+ If, for example, your header line is already formatted as <gui>Huge</gui>, then you just need to make it
also <gui>Bold</gui> to turn it into a header of level 1.
+ See <link xref="editing-notes"/> to know how to set text style.
+</p>
+
+</section>
+
+
+<section id="showtable"><title>Showing the table of content</title>
+
+<p>You can access the table of content, either:</p>
+<list>
+<item><p>in the <guiseq><gui>toolbar</gui><gui>Tools</gui><gui>Table of Content</gui></guiseq>
menu</p></item>
+<item><p>in the <guiseq><gui>contextual menu</gui><gui>Table of Content</gui></guiseq>
(<keyseq>right-click</keyseq> on the note window)</p></item>
+<item><p>in a <gui>popup menu</gui>, with the keyboard shortcut
<keyseq><key>Ctrl</key><key>Alt</key><key>1</key></keyseq></p></item>
+<p>Then you can navigate up and down with the <gui>arrow keys</gui> and jump to the selected header with
<key>enter</key>. Or just <keyseq>click</keyseq> with your mouse on the header to jump to.</p>
+</list>
+
+</section>
+
+
+<section id="troubleshooting"><title>Troubleshooting</title>
+<terms>
+ <item><title><em style="strong">One header does not show in the table of content</em></title><p>
+ there might be some characters in the header line, like whitespaces, which are not formatted as a
header. Make sure that <em>the whole line</em> is formatted as a header. See <link xref="#setheaders"/>.</p>
+ </item>
+ <item><title><em style="strong">There is an empty line in the table of content</em></title><p>
+ an empty line, possibly with whitespaces, is formatted as a header. Jump to this line, and delete the
area.</p>
+ </item>
+
+ <item><title></title><p>
+ </p>
+ </item>
+
+</terms>
+
+</section>
+
+</page>
\ No newline at end of file
diff --git a/help/Makefile.am b/help/Makefile.am
index 7c36510..4aa87bb 100644
--- a/help/Makefile.am
+++ b/help/Makefile.am
@@ -32,6 +32,7 @@ HELP_FILES = \
gnote-addin-replacetitle.page \
gnote-addin-sync-local.page \
gnote-addin-sync-webdav.page \
+ gnote-addin-tableofcontent.page \
gnote-addin-timestamp.page \
gnote-addin-underline.page \
gnote-bulleted-lists.page \
diff --git a/po/POTFILES.in b/po/POTFILES.in
index f5f2352..ce34cd5 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -31,6 +31,8 @@ src/addins/statistics/statisticsapplicationaddin.cpp
src/addins/statistics/statisticswidget.cpp
src/addins/stickynoteimport/stickynoteimport.desktop.in
src/addins/stickynoteimport/stickynoteimportnoteaddin.cpp
+src/addins/tableofcontent/tableofcontent.desktop.in
+src/addins/tableofcontent/tableofcontentnoteaddin.cpp
src/addins/tomboyimport/tomboyimport.desktop.in
src/addins/underline/underline.desktop.in
src/addins/underline/underlinemenuitem.cpp
diff --git a/src/addins/Makefile.am b/src/addins/Makefile.am
index 6d211d3..3df3e82 100644
--- a/src/addins/Makefile.am
+++ b/src/addins/Makefile.am
@@ -13,6 +13,7 @@ SUBDIRS = backlinks \
replacetitle \
statistics \
stickynoteimport \
+ tableofcontent \
tomboyimport \
underline \
webdavsyncservice \
diff --git a/src/addins/tableofcontent/Makefile.am b/src/addins/tableofcontent/Makefile.am
new file mode 100644
index 0000000..2c87d23
--- /dev/null
+++ b/src/addins/tableofcontent/Makefile.am
@@ -0,0 +1,23 @@
+
+include $(builddir)/../addins.mk
+
+ INTLTOOL_DESKTOP_RULE@
+
+desktop_in_files = tableofcontent.desktop.in
+desktop_files = $(desktop_in_files:.desktop.in=.desktop)
+
+addinsdir = $(ADDINSDIR)
+addins_LTLIBRARIES = tableofcontent.la
+addins_DATA = $(desktop_files)
+
+
+tableofcontent_la_SOURCES = \
+ tableofcontent.hpp \
+ tableofcontentnoteaddin.hpp \
+ tableofcontentnoteaddin.cpp \
+ tableofcontentmenuitem.hpp \
+ tableofcontentmenuitem.cpp \
+ $(NULL)
+
+EXTRA_DIST = $(desktop_in_files)
+DISTCLEANFILES = $(desktop_files)
diff --git a/src/addins/tableofcontent/NEWS b/src/addins/tableofcontent/NEWS
new file mode 100644
index 0000000..cf71afe
--- /dev/null
+++ b/src/addins/tableofcontent/NEWS
@@ -0,0 +1,60 @@
+NEWS for Add-in: Table of Content
+=================================
+
+(NOTE: little release manual:
+ update NEWS + .desktop version/enabled=false + help topic status/pkgversion ==> commit -m "version x.y")
+
+
+== 0.9
+- renamed labels "Level 1 Header" to "Header Level 1" (resp. 2)
+- set help topic status to "candidate"
+- typo in .desktop description
+- code: general code review, various minor updates in code, including:
+ - add-in description in copyright headers
+ - various code comments
+ - renamed header level enum: s/Level/Header/ and s/H1,H2,H3/Title,Level_1,Level_2/
+ (so forget the "HTML alike", now Ctrl-1/2 matches Level_1/2 (instead of H2/H3!))
+ - renamed get_range_level() into get_header_level_for_range()
+
+== 0.8
+- Added Help entry in toc menu
+- Set Ctrl-Alt-1 accelerator on toc menu item
+- Removed "Show in a Popup Menu" entry in toc menu
+- Don't show action entries in detatched popup.
+- Don't show (empty toc) label on menus with action entries.
+- Removed italic on action menu entries
+
+== 0.7
+- ported to master/3.9.0 by Aurimas
+- .desktop.in, use unicode ©, set Authors and Copyright not translatable
+- added NEWS file
+- when toc is empty, use just a dummy unsensitive item rather than an explanatory text.
+ explanations will be in the manual/help.
+- added menu entries to set headers level 1 and 2, with Ctrl-1/2 accelerators
+- added menu entry to show the accelerator to open the toc in a popup menu
+- toc action entries set in italic to differentiate from the toc entries
+- "Show in a popup menu" action set unsensitive (it does not make sense to trigger it from a menu)
+- added help page
+
+== 0.6
+- code cleanup from Aurimas review
+
+== 0.5
+- now compiles with gnote-3.6.0
+
+== 0.4
+- fixed segfault and double menu bug (I think so)
+- code cleanup
+
+== 0.3
+- added TableofcontentModule::copyright()
+- used a namespaced-enum for header Levels. New file tableofcontent.hpp
+- code review changes (https://bugzilla.gnome.org/show_bug.cgi?id=698059)
+
+== 0.2
+- add toc submenu in contextual menu
+- Ctrl-Alt-1 opens toc in a popup menu
+
+== 0.1
+- port from Tomboy version, for gnote-0.7.6
+ https://github.com/oluc/tomboy/tree/TableOfContentAddin/Tomboy/Addins/TableOfContent
diff --git a/src/addins/tableofcontent/TODO b/src/addins/tableofcontent/TODO
new file mode 100644
index 0000000..dfd45b6
--- /dev/null
+++ b/src/addins/tableofcontent/TODO
@@ -0,0 +1,108 @@
+TODO for Add-in: Table of Content
+=================================
+
+
+- On Ctrl-1/2 toggle, toggle only B/L/H tags, not all tags
+ (this is a bug!)
+ ex: within all fixed width text, setting a header, the header must remain also fixed width
+
+- Huge is not huge enough
+ There is little visual difference between large and huge
+ if large uses uppercase and huge lowercase it makes the difference thiner
+ it also depends on the letters, as some takes visually more space
+ when they are close to each other it may help to distinguish
+ when there is only one header in the window, it's hard to say if it's of level 1 or 2
+
+ See https://bugzilla.gnome.org/show_bug.cgi?id=657601
+ Could also be: general config options for font sizes/factor (for S/N/L/H)
+ Could also be: allow any sizes <size:n>, with n = factor (not only S/N/L/H)
+
+- Highlight the header when jumping to it
+ ==> More visual, especially when the header does not scroll up to the head of the window
+ remove highlight as soon as cursor moved
+ (like search results, for example)
+
+- When no headers, still show the note title in toc
+ this is usefull to jump to the top of a long (unstructured) note
+
+- Check all FIXMEs, and more code cleanup
+
+
+== Maybe
+
+- Undo as a single user action, when setting headers
+ Note: tomboy/gnote handles poorly undo/redo,
+ this item may need to upgrade the undo system
+
+- When entering header text, stop formatting on 'enter'
+ UC: 1. cursor at beginning of a line
+ 2. Ctrl-1/2
+ 3. enter header title
+ 4. press 'enter'
+ --> currently: if you keep typing text, the new line keep being bold+huge/large
+ --> wanted: stop formatting as a header.
+ /!\ this conflicts with a user who actually *wants* to type bold+huge/large *text* with new lines
+ ==> when entering a header, to move back to text formatting: arrow down, or Ctrl-1/2
+ TO CHECK: does the later actually works?
+
+- Set where the toc menu item appears in the Tools menu
+ --> next to "What Links Here?"
+ (I think there is a way to say where)
+
+- Keyboard shortcuts for jumping between sessions
+ Jump to next section
+ Jump to previous section
+ Q: What shortcuts? the ones with up/down arrow ar all(?) taken?
+ Alt-right and Alt-left, usually used for prev/next, are used for bullet list indentation
+ (can this change?)
+
+- Customizable header tags
+ « a header level x is a full line with tags Tx »
+
+ Each Header has:
+ - a list of tags ex: "bold + size:huge"
+ - a level gint
+ - a keyboard shortcut by default Ctrl+<header level>
+ - an icon (or not)
+ - a Unicode string (or not) to tabulate the header in the toc
+ Ex:
+ L key tag list icon tab string
+ --------------------------------------------------------------------
+ 1 Ctrl+1 "bold + size:huge" "stock:GO_FORWARD" ""
+ 2 Ctrl+2 "bold + size:large" "" "└→"
+ 3 Ctrl+3 "underline" "" " •"
+
+ Todo: make code generic + (g)settings + preference UI + help topic
+
+
+== Maybe not
+
+- Headers could (also?) have a syntax (vs text formatting)
+ For example a prefix, or prefix + suffix
+ like text lightweight markup languages (asciidoc/markdown/etc.)
+ ex: == Chapter
+ ex: === Section
+ ex: ==== Subsection
+
+- Section cross references
+ if header "FooBar" exists, #FooBar is shown as a link
+ when activating #FooBar, it jumps to the section
+ Maybe also: AnotherNote#Foo open AnotherNote and jumps to Foo section
+ Then it would allow URI like note://note-reference#here
+ Note: need better syntax than just '#'
+ Note: maybe strip whitespaces before comparing? (?)
+ ex: "See also #Resources sction below" --> Resources
+ /!\ need to cross update, if a section name is changed/removed
+ --> need to listen to all changes, maybe to heavy?
+ --> or would need to set specific tags for sections and xrefs(?)
+
+- More shortcuts for formatting? + configuration panel?
+ Ctrl-shift-B
+ Ctrl-shift-H
+ Ctrl-shift-L
+ Ctrl-shift-B-L
+ Ctrl-shift-B-H
+ (update: I don't remember what it's meant to do! Need to check Tomboy mailinglist)
+ (update: I think it's from the time where Ctrl-1 would set the whole line(s) where the cursor or
selection is. So these shortcuts would set the whole line(s) with corresponding formatting tags)
+ Then we could have Ctrl-Shift-1 and Ctrl-Shift-2
+ Though I disabled this because of some misfunction(?) (or a just bug?)(?)
diff --git a/src/addins/tableofcontent/tableofcontent.desktop.in
b/src/addins/tableofcontent/tableofcontent.desktop.in
new file mode 100644
index 0000000..daac4f3
--- /dev/null
+++ b/src/addins/tableofcontent/tableofcontent.desktop.in
@@ -0,0 +1,10 @@
+[AddinInfo]
+Id=TableofcontentAddin
+_Name=Table of Content
+_Description=Navigate long structured notes. Set section and subsection headers in your note, and the Table
of Content will show in a menu.
+Authors=Luc Pionchon
+Category=Tools
+Version=0.9
+DefaultEnabled=false
+Module=tableofcontent
+Copyright=© 2013 Luc Pionchon
diff --git a/src/addins/tableofcontent/tableofcontent.hpp b/src/addins/tableofcontent/tableofcontent.hpp
new file mode 100644
index 0000000..7257858
--- /dev/null
+++ b/src/addins/tableofcontent/tableofcontent.hpp
@@ -0,0 +1,47 @@
+/*
+ * "Table of Content" is a Note add-in for Gnote.
+ * It lists Note's table of content in a menu.
+ *
+ * Copyright (C) 2013 Luc Pionchon <pionchon luc gmail com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* An enum for different header levels in the toc */
+
+
+/* Note: the enum is in this file because
+ when it was in tableofcontentnoteaddin.hpp,
+ I could not use it also in tableofcontentmenuitem.cpp,
+ there was a scope error, which I could not solve.
+ */
+
+#ifndef __TABLEOFCONTENT_HPP_
+#define __TABLEOFCONTENT_HPP_
+
+namespace tableofcontent {
+
+namespace Header { // Header level,
+ enum Type { // Header::Type (can be used as a type)
+ Title, // Header::Title == Note title
+ Level_1, // Header::Level_1 == 1st level header == Ctrl-1
+ Level_2, // Header::Level_2 == 2nd level header == Ctrl-2
+ None // Header::None
+ };
+}
+
+
+}
+
+#endif
\ No newline at end of file
diff --git a/src/addins/tableofcontent/tableofcontentmenuitem.cpp
b/src/addins/tableofcontent/tableofcontentmenuitem.cpp
new file mode 100644
index 0000000..c63c1db
--- /dev/null
+++ b/src/addins/tableofcontent/tableofcontentmenuitem.cpp
@@ -0,0 +1,88 @@
+/*
+ * "Table of Content" is a Note add-in for Gnote.
+ * It lists Note's table of content in a menu.
+ *
+ * Copyright (C) 2013 Luc Pionchon <pionchon luc gmail com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* A subclass of ImageMenuItem to show a toc menu item */
+
+#include <gtkmm/stock.h>
+
+#include "iconmanager.hpp"
+#include "notewindow.hpp"
+
+#include "tableofcontentmenuitem.hpp"
+#include "tableofcontent.hpp"
+
+namespace tableofcontent {
+
+
+TableofcontentMenuItem::TableofcontentMenuItem (
+ const gnote::Note::Ptr & note,
+ const std::string & header,
+ Header::Type header_level,
+ int header_position)
+ : m_note (note)
+ , m_header_position (header_position)
+{
+ //Create a new menu item, with style depending on the header level:
+ /* +-----------------+
+ |[] NOTE TITLE | <---- Title == note icon + bold note title
+ | > Header 1 | <---- Level_1 == arrow icon + header title
+ | > Header 1 |
+ | └→ header 2 | <---- Level_2 == (no icon) + indent string + header title
+ | └→ header 2 |
+ | └→ header 2 |
+ | > Header 1 |
+ +-----------------+
+ */
+
+ set_use_underline (false); //we don't want potential '_' in the header to be used as mnemonic
+
+ if (header_level == Header::Title) {
+ set_image(*manage(new Gtk::Image(gnote::IconManager::obj().get_icon(gnote::IconManager::NOTE, 16))));
+ Gtk::Label *label = (Gtk::Label*)get_child();
+ label->set_markup("<b>" + header + "</b>");
+ }
+ else if (header_level == Header::Level_1) {
+ set_image(*manage(new Gtk::Image(Gtk::Stock::GO_FORWARD, Gtk::ICON_SIZE_MENU)));
+ set_label(header);
+ }
+ else if (header_level == Header::Level_2) {
+ set_label("└→ " + header);
+ }
+}
+
+
+void TableofcontentMenuItem::on_activate ()
+{
+ if (!m_note) {
+ return;
+ }
+
+ // Scroll the TextView and place the cursor on the header
+ Gtk::TextIter header_iter;
+ header_iter = m_note->get_buffer()->get_iter_at_offset (m_header_position);
+ m_note->get_window()->editor()->scroll_to (header_iter,
+ 0.0, //[0.0,0.5] within_margin, margin as a fraction of screen
size.
+ 0.0, //[0.0,1.0] horizontal alignment of mark within visible
area.
+ 0.0);//[0.0,1.0] vertical alignment of mark within visible
area.
+ m_note->get_buffer()->place_cursor (header_iter);
+}
+
+
+} //namespace
\ No newline at end of file
diff --git a/src/addins/tableofcontent/tableofcontentmenuitem.hpp
b/src/addins/tableofcontent/tableofcontentmenuitem.hpp
new file mode 100644
index 0000000..e1d92f8
--- /dev/null
+++ b/src/addins/tableofcontent/tableofcontentmenuitem.hpp
@@ -0,0 +1,56 @@
+/*
+ * "Table of Content" is a Note add-in for Gnote.
+ * It lists Note's table of content in a menu.
+ *
+ * Copyright (C) 2013 Luc Pionchon <pionchon luc gmail com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* A subclass of ImageMenuItem to show a toc menu item */
+
+#ifndef __TABLEOFCONTENT_MENU_ITEM_HPP_
+#define __TABLEOFCONTENT_MENU_ITEM_HPP_
+
+#include <string>
+#include <gtkmm/imagemenuitem.h>
+
+#include "note.hpp"
+#include "tableofcontent.hpp"
+
+
+namespace tableofcontent {
+
+class TableofcontentMenuItem : public Gtk::ImageMenuItem
+{
+public:
+ TableofcontentMenuItem ( const gnote::Note::Ptr & note,
+ const std::string & header,
+ Header::Type header_level,
+ int header_position
+ );
+
+protected:
+ virtual void on_activate ();
+
+private:
+ gnote::Note::Ptr m_note; //the Note referenced by the menu item
+ int m_header_position; //the position of the header in the Note
+ // == offset in the GtkTextBuffer
+};
+
+
+}
+
+#endif
\ No newline at end of file
diff --git a/src/addins/tableofcontent/tableofcontentnoteaddin.cpp
b/src/addins/tableofcontent/tableofcontentnoteaddin.cpp
new file mode 100644
index 0000000..3360836
--- /dev/null
+++ b/src/addins/tableofcontent/tableofcontentnoteaddin.cpp
@@ -0,0 +1,368 @@
+/*
+ * "Table of Content" is a Note add-in for Gnote.
+ * It lists Note's table of content in a menu.
+ *
+ * Copyright (C) 2013 Luc Pionchon <pionchon luc gmail com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* A subclass of NoteAddin, implementing the Table of Content add-in */
+
+#include <glibmm/i18n.h>
+
+#include <gtkmm/stock.h>
+#include <gtkmm/separatormenuitem.h>
+
+#include "sharp/string.hpp"
+
+#include "notemanager.hpp"
+#include "notewindow.hpp"
+#include "notebuffer.hpp"
+#include "utils.hpp"
+
+#include "tableofcontent.hpp"
+#include "tableofcontentnoteaddin.hpp"
+#include "tableofcontentmenuitem.hpp"
+
+namespace tableofcontent {
+
+TableofcontentModule::TableofcontentModule()
+{
+ ADD_INTERFACE_IMPL(TableofcontentNoteAddin);
+}
+
+
+TableofcontentNoteAddin::TableofcontentNoteAddin()
+ : m_menu_item (NULL)
+ , m_toc_menu (NULL)
+ , m_toc_menu_built (false)
+{
+}
+
+void TableofcontentNoteAddin::initialize () {}
+void TableofcontentNoteAddin::shutdown () {}
+
+
+Gtk::ImageMenuItem * new_toc_menu_item ()
+//create a menu item like: "[]_Table_of_Content______Ctrl-Alt-1__>"
+{
+ Gtk::ImageMenuItem * menu_item = manage(new Gtk::ImageMenuItem ());
+ menu_item->set_image(*manage(new Gtk::Image(Gtk::Stock::JUMP_TO, Gtk::ICON_SIZE_MENU)));
+
+ Gtk::AccelLabel *acclabel = manage(new Gtk::AccelLabel(_("Table of Content")));
+ acclabel->set_alignment (Gtk::ALIGN_START);
+ /* I don't have gtkmm-3.6, but I have gtk-3.6 */
+ /* TO UNCOMMENT *///acclabel->set_accel (GDK_KEY_1, Gdk::CONTROL_MASK | Gdk::MOD1_MASK);
+ /* TO DELETE */gtk_accel_label_set_accel (acclabel->gobj (),GDK_KEY_1, GdkModifierType
(GDK_CONTROL_MASK | GDK_MOD1_MASK));
+ acclabel->show ();
+
+ menu_item->add (*acclabel);
+
+ return menu_item;
+}
+
+
+void TableofcontentNoteAddin::on_note_opened ()
+{
+ // TOC menu
+ m_toc_menu = manage(new Gtk::Menu());
+ m_toc_menu->signal_hide().connect(
+ sigc::mem_fun(*this, &TableofcontentNoteAddin::on_menu_hidden));
+ m_toc_menu->show_all ();
+
+ m_menu_item = new_toc_menu_item ();
+ m_menu_item->set_submenu(*m_toc_menu);
+ m_menu_item->signal_activate().connect(
+ sigc::mem_fun(*this, &TableofcontentNoteAddin::on_menu_item_activated));
+ m_menu_item->show ();
+
+ add_plugin_menu_item (m_menu_item);
+
+ // Reacts to key press events
+ get_note()->get_window()->signal_key_press_event().connect(
+ sigc::mem_fun(*this, &TableofcontentNoteAddin::on_key_pressed));
+
+ // TOC can show up also in the contextual menu
+ get_note()->get_window()->editor()->signal_populate_popup().connect(
+ sigc::mem_fun(*this, &TableofcontentNoteAddin::on_populate_popup));
+
+ // Header tags
+ m_tag_bold = get_note()->get_tag_table()->lookup ("bold");
+ m_tag_large = get_note()->get_tag_table()->lookup ("size:large");
+ m_tag_huge = get_note()->get_tag_table()->lookup ("size:huge");
+}
+
+
+void TableofcontentNoteAddin::on_menu_item_activated ()
+{
+ if(m_toc_menu_built) {
+ return;
+ }
+ populate_toc_menu (m_toc_menu);
+ m_toc_menu_built = true;
+}
+
+
+void TableofcontentNoteAddin::on_menu_hidden ()
+{
+ m_toc_menu_built = false; //force the submenu to rebuild next time it's supposed to show
+}
+
+
+void TableofcontentNoteAddin::populate_toc_menu (Gtk::Menu *toc_menu, bool has_action_entries)
+//populate a menu with Note's table of content
+{
+ // Clear out the old list
+ std::vector<Gtk::Widget*> menu_items = toc_menu->get_children();
+ for(std::vector<Gtk::Widget*>::reverse_iterator iter = menu_items.rbegin();
+ iter != menu_items.rend(); ++iter) {
+ toc_menu->remove(**iter);
+ }
+
+ // Build a new list
+ std::list<TableofcontentMenuItem*> items;
+ get_tableofcontent_menu_items(items);
+
+ for(std::list<TableofcontentMenuItem*>::iterator iter = items.begin();
+ iter != items.end(); ++iter) {
+ TableofcontentMenuItem *item(*iter);
+ item->show_all();
+ toc_menu->append(*item);
+ }
+
+ // Action menu items, or nothing
+ if (has_action_entries == false) {
+ if (toc_menu->get_children().size() == 0) { // no toc items, and no action entries = empty menu
+ Gtk::MenuItem *item = manage(new Gtk::MenuItem(_("(empty table of content)")));
+ item->set_sensitive(false);
+ item->show();
+ toc_menu->append(*item);
+ }
+ }
+ else {
+ Gtk::MenuItem *item;
+
+ if (toc_menu->get_children().size() != 0) { //there are toc items, we add a separator
+ item = manage(new Gtk::SeparatorMenuItem ());
+ item->show ();
+ toc_menu->append(*item);
+ }
+
+ item = manage(new Gtk::MenuItem (_("Header Level 1")));
+ item->add_accelerator("activate", get_note()->get_window()->get_accel_group(), GDK_KEY_1,
Gdk::CONTROL_MASK, Gtk::ACCEL_VISIBLE);
+ item->signal_activate().connect(sigc::mem_fun(*this, &TableofcontentNoteAddin::on_level_1_activated));
+ item->show ();
+ toc_menu->append(*item);
+
+ item = manage(new Gtk::MenuItem (_("Header Level 2")));
+ item->add_accelerator("activate", get_note()->get_window()->get_accel_group(), GDK_KEY_2,
Gdk::CONTROL_MASK, Gtk::ACCEL_VISIBLE);
+ item->signal_activate().connect(sigc::mem_fun(*this, &TableofcontentNoteAddin::on_level_2_activated));
+ item->show ();
+ toc_menu->append(*item);
+
+ item = manage(new Gtk::MenuItem (_("Table of Content Help")));
+ item->signal_activate().connect(sigc::mem_fun(*this, &TableofcontentNoteAddin::on_toc_help_activated));
+ item->show ();
+ toc_menu->append(*item);
+ }
+
+}
+
+
+void TableofcontentNoteAddin::on_populate_popup (Gtk::Menu* popup_menu)
+//prepened a toc submenu in the contextual menu
+{
+ Gtk::Menu *toc_menu = manage(new Gtk::Menu());
+ populate_toc_menu (toc_menu);
+
+ Gtk::SeparatorMenuItem *separator = manage(new Gtk::SeparatorMenuItem ());
+ separator->show ();
+ popup_menu->prepend (*separator);
+
+ Gtk::ImageMenuItem *menu_item = new_toc_menu_item ();
+ menu_item->set_submenu (*toc_menu);
+ menu_item->show ();
+
+ popup_menu->prepend (*menu_item);
+}
+
+
+bool TableofcontentNoteAddin::has_tag_over_range (Glib::RefPtr<Gtk::TextTag> tag, Gtk::TextIter start,
Gtk::TextIter end)
+//return true if tag is set from start to end
+{
+ bool has = false;
+ Gtk::TextIter iter = start;
+ while (iter.compare(end) != 0 && (has = iter.has_tag(tag))){
+ iter.forward_char();
+ }
+ return has;
+}
+
+
+Header::Type TableofcontentNoteAddin::get_header_level_for_range (Gtk::TextIter start, Gtk::TextIter end)
+//return the header level from start to end
+{
+ if (has_tag_over_range (m_tag_bold, start, end)) {
+
+ if (has_tag_over_range (m_tag_huge , start, end)) {
+ return Header::Level_1;
+ }
+ else if (has_tag_over_range (m_tag_large, start, end)) {
+ return Header::Level_2;
+ }
+ else {
+ return Header::None;
+ }
+ }
+ else {
+ return Header::None;
+ }
+}
+
+
+void TableofcontentNoteAddin::get_tableofcontent_menu_items(std::list<TableofcontentMenuItem*> & items)
+//go through the note text, and list all lines tagged as header,
+//and for each header, create a new TableofcontentMenuItem.
+{
+ TableofcontentMenuItem *item = NULL;
+
+ std::string header;
+ Header::Type header_level;
+ int header_position;
+
+ Gtk::TextIter iter, iter_end, eol;
+
+ //for each line of the buffer,
+ //check if the full line has bold and (large or huge) tags
+ iter = get_note()->get_buffer()->begin();
+ iter_end = get_note()->get_buffer()->end();
+
+ while (iter != iter_end) {
+ eol = iter;
+ eol.forward_to_line_end();
+
+ header_level = get_header_level_for_range (iter, eol);
+
+ if (header_level == Header::Level_1 || header_level == Header::Level_2) {
+ header_position = iter.get_offset();
+ header = iter.get_text(eol);
+
+ if (items.size() == 0) {
+ //It's the first header found,
+ //we also insert an entry linked to the Note's title:
+ item = manage(new TableofcontentMenuItem (get_note(), get_note()->get_title(), Header::Title, 0));
+ items.push_back(item);
+ }
+ item = manage(new TableofcontentMenuItem (get_note(), header, header_level, header_position));
+ items.push_back(item);
+ }
+ iter.forward_visible_line(); //next line
+ }
+}
+
+void TableofcontentNoteAddin::on_level_1_activated()
+{
+ headification_switch (Header::Level_1);
+}
+void TableofcontentNoteAddin::on_level_2_activated()
+{
+ headification_switch (Header::Level_2);
+}
+void TableofcontentNoteAddin::on_toc_popup_activated()
+{
+ if(m_toc_menu_built == false) {
+ populate_toc_menu(m_toc_menu, false);
+ m_toc_menu_built = true;
+ }
+ m_toc_menu->popup(0, 0);
+}
+void TableofcontentNoteAddin::on_toc_help_activated()
+{
+ gnote::NoteWindow* window = get_note()->get_window();
+ gnote::utils::show_help("gnote", "addin-tableofcontent",
+ window->get_screen()->gobj(), dynamic_cast<Gtk::Window*>(window->host()));
+}
+
+
+bool TableofcontentNoteAddin::on_key_pressed(GdkEventKey *ev)
+//return true if signal handled, false otherwise
+//NOTE: if a menu item has an accelerator,
+// its entry is needed until the toc menu is built a first time,
+// then the menu item accelerator takes the signals.
+{
+ switch(ev->keyval) {
+
+ case GDK_KEY_1:
+ if (ev->state == (GDK_CONTROL_MASK | GDK_MOD1_MASK)) {// Ctrl-Alt-1
+ on_toc_popup_activated();
+ return true;
+ }
+ else if (ev->state == GDK_CONTROL_MASK) { // Ctrl-1
+ on_level_1_activated ();
+ return true;
+ }
+ else {
+ return false;
+ }
+ break;
+
+ case GDK_KEY_2:
+ if (ev->state == GDK_CONTROL_MASK) { // Ctrl-2
+ on_level_2_activated ();
+ return true;
+ }
+ else {
+ return false;
+ }
+ break;
+
+ default:
+ return false;
+ }
+
+ return false;
+}
+
+
+void TableofcontentNoteAddin::headification_switch (Header::Type header_request)
+//apply the correct header style to the current selection
+//switch: Level_1 <--> Level_2 <--> text
+{
+ Glib::RefPtr<gnote::NoteBuffer> buffer = get_note()->get_buffer();
+ Gtk::TextIter start, end;
+
+ buffer->get_selection_bounds (start, end);
+
+ Header::Type current_header = get_header_level_for_range (start, end);
+
+ buffer->remove_all_tags (start, end);//reset all tags
+
+ if( current_header == Header::Level_1 && header_request == Header::Level_2) { //existing vs requested
+ buffer->set_active_tag ("bold");
+ buffer->set_active_tag ("size:large");
+ }
+ else if( current_header == Header::Level_2 && header_request == Header::Level_1) {
+ buffer->set_active_tag ("bold");
+ buffer->set_active_tag ("size:huge");
+ }
+ else if( current_header == Header::None) {
+ buffer->set_active_tag ("bold");
+ buffer->set_active_tag ( (header_request == Header::Level_1)?"size:huge":"size:large");
+ }
+
+}
+
+
+} //namespace
\ No newline at end of file
diff --git a/src/addins/tableofcontent/tableofcontentnoteaddin.hpp
b/src/addins/tableofcontent/tableofcontentnoteaddin.hpp
new file mode 100644
index 0000000..7a799a8
--- /dev/null
+++ b/src/addins/tableofcontent/tableofcontentnoteaddin.hpp
@@ -0,0 +1,95 @@
+/*
+ * "Table of Content" is a Note add-in for Gnote.
+ * It lists Note's table of content in a menu.
+ *
+ * Copyright (C) 2013 Luc Pionchon <pionchon luc gmail com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* A subclass of NoteAddin, implementing the Table of Content add-in */
+
+#ifndef __TABLEOFCONTENT_NOTEADDIN_HPP_
+#define __TABLEOFCONTENT_NOTEADDIN_HPP_
+
+#include <list>
+
+#include <gtkmm/imagemenuitem.h>
+#include <gtkmm/menu.h>
+
+#include "sharp/dynamicmodule.hpp"
+#include "note.hpp"
+#include "noteaddin.hpp"
+
+#include "tableofcontent.hpp"
+
+
+namespace tableofcontent {
+
+class TableofcontentModule : public sharp::DynamicModule
+{
+public:
+ TableofcontentModule();
+};
+DECLARE_MODULE(TableofcontentModule);
+
+class TableofcontentMenuItem;
+
+
+class TableofcontentNoteAddin : public gnote::NoteAddin
+{
+public:
+ static TableofcontentNoteAddin *create()
+ {
+ return new TableofcontentNoteAddin;
+ }
+ TableofcontentNoteAddin();
+
+ virtual void initialize ();
+ virtual void shutdown ();
+ virtual void on_note_opened ();
+
+private:
+ void on_menu_item_activated ();
+ void on_menu_hidden ();
+ bool on_key_pressed (GdkEventKey *ev);
+ void on_populate_popup (Gtk::Menu* popup_menu);
+ void on_level_1_activated ();
+ void on_level_2_activated ();
+ void on_toc_popup_activated ();
+ void on_toc_help_activated ();
+
+
+ void populate_toc_menu (Gtk::Menu *toc_menu, bool has_action_entries = true);
+
+ bool has_tag_over_range (Glib::RefPtr<Gtk::TextTag> tag, Gtk::TextIter start, Gtk::TextIter end);
+ Header::Type get_header_level_for_range (Gtk::TextIter start, Gtk::TextIter end);
+
+ void get_tableofcontent_menu_items (std::list<TableofcontentMenuItem*> & items);
+
+ void headification_switch (Header::Type header_request);
+
+ Gtk::ImageMenuItem *m_menu_item; // the TOC menu item, in the Tools menu
+ Gtk::Menu *m_toc_menu; // the TOC submenu, containing the TOC
+ bool m_toc_menu_built; // whereas toc_menu is already built
+
+ Glib::RefPtr<Gtk::TextTag> m_tag_bold; // the tags used to mark headers
+ Glib::RefPtr<Gtk::TextTag> m_tag_large;
+ Glib::RefPtr<Gtk::TextTag> m_tag_huge;
+};
+
+
+}
+
+#endif
\ No newline at end of file
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]