← Back to team overview

zim-wiki team mailing list archive

faster creation of notes

 

  Hello:
  In my process of learning python + gtk, I've created a zim mock up to
try out a concept. The idea is to make creation of notes a bit faster,
to achieve mind-map speed, but keeping the current treeview used in zim.
This is how it works:

  * Use arrows to move in the treeview, enter to select a note and
control+space to switch to the editor and back, as usual
  * Use alt+arrows to create notes within the TreeView, using the
editable property of this widget. (alt+left for children, alt+down for
sibling)
  * When there are children of the Template folder, if a new note is
created, you might type the template name and hit enter. Then the text
from the template is copied to the new note, and the cell will become
editable one more time so that you can introduce the real name of this note.

  There are two files attached (unless trimmed by the mail manager, in
which case you can copy and paste the files at the end of the email). It
is run by writing:

python zimmindmap.py

  The other file was generated by glade: it is a gtkbuilder file and it
doesn't need any libraries. It has a mock up menu which is totally
useless, and probably in spanish. The template part should really be
better with autocompletion, and maybe it should use grandchildren of the
Templates folder into, but anyway this is just a mockup.

  Do you like this way of creating notes, and/or using Templates?

Regards

------------------------------- zimmindmap.py
-------------------------------
import sys
import gtk

class ZimMindMap(object):
    """ mock up of zim to test an idea """
    temptitle = 'Title'
    templatechar = '.'
   
    def __init__ (self):
        """ Class initialiser """
        self.notes={}
        self.current_note = None
       
        self.builder = gtk.Builder()
        self.builder.add_from_file("zimmindmap.glade")
       
        self.window = self.builder.get_object("mainwindow")
        self.noteeditor = self.builder.get_object("noteeditor")
        self.noteindex = self.builder.get_object("index")

        self.datamodel = gtk.TreeStore(str)

        self.cellrender=gtk.CellRendererText() # renderer para la
primera columna
        self.title_column = gtk.TreeViewColumn('Notes')
        self.title_column.pack_start(self.cellrender,True)
        self.title_column.add_attribute(self.cellrender, "text", 0)
        self.noteindex.append_column(self.title_column)

        uno = self.newnote('Hello1')
        dos = self.newnote('Hello2')
        self.newnote('Hello11',uno)
        self.newnote('Hello12',uno)
        self.newnote('Hello21',dos)
        self.newnote('Hello22',dos)
        templates_iter=self.newnote('Templates')
        self.templates_root = self.datamodel.get_path(templates_iter)

        self.noteindex.set_model(self.datamodel)
        self.builder.connect_signals(self)      

    def newnote(self, title, parent=None, texto=None):
        it = self.datamodel.append(parent, (title,))
        path = self.datamodel.get_path(it)
        if not texto:
            texto=title
        self.notes[path] = texto
        return it

    def delnote(self, path):
        iter=self.datamodel.get_iter(path)
        self.datamodel.remove(iter)
        del self.notes[path]

    def on_mainwindow_destroy(self,widget,data=[]):
        gtk.main_quit()

    def on_mainwindow_key_release_event(self,widget,data=[]):
        if data.keyval==32  and (data.state& gtk.gdk.CONTROL_MASK):  
#Control+space
            if self.noteeditor.is_focus():
                self.noteindex.grab_focus()
            else:
                self.noteeditor.grab_focus()
            return True
    def on_index_key_press_event(self,widget,data=[]):
        #65361: left, 65362:up, 65363: right, 65364:down, 65293:Enter,
32:space
        if data.keyval==65363:   #right
            current_row,current_column=widget.get_cursor()
            current_iter=self.datamodel.get_iter(current_row)
            widget.expand_row(current_row,False)
            if data.state & gtk.gdk.MOD1_MASK:#Alt+Left
                new_note_iter=self.newnote(ZimMindMap.temptitle,
parent=current_iter)
                new_note_path=self.datamodel.get_path(new_note_iter)
#                widget.expand_row(new_note_path,True)  #doesn't work if
current_row only has just this child
                widget.expand_row(current_row,True)     #not the right
thing, but works
                self.cellrender.set_property('editable',True)
               
self.cellrender.connect('edited',self.edited_cell,self.datamodel)
                self.noteindex.set_cursor(new_note_path,
focus_column=self.title_column ,start_editing=True)
        elif data.keyval==65364 and (data.state&
gtk.gdk.MOD1_MASK):#Alt+down
            current_row,current_column=widget.get_cursor()
            current_iter=self.datamodel.get_iter(current_row)
            parent_iter=self.datamodel.iter_parent(current_iter)
            parent_path=self.datamodel.get_path(parent_iter) if
parent_iter else ()
            new_note_iter=self.newnote(ZimMindMap.temptitle,
parent=parent_iter)
            new_note_path=self.datamodel.get_path(new_note_iter)
            if parent_path:
                widget.expand_row(parent_path,True)     #not the right
thing, but works
            self.cellrender.set_property('editable',True)
           
self.cellrender.connect('edited',self.edited_cell,self.datamodel)
            self.noteindex.set_cursor(new_note_path,
focus_column=self.title_column ,start_editing=True)
        elif data.keyval==65361:  #left
            current_row,current_column=widget.get_cursor()
            current_iter=self.datamodel.get_iter(current_row)
            widget.collapse_row(current_row)
        elif data.keyval==65293 or data.keyval==32:   #Enter or space
            selection = widget.get_selection()
            model,iter = selection.get_selected()
            path = self.datamodel.get_path(iter)
            self.show_note(path)
            return True

    def on_index_cursor_changed(self,widget,data=None):
        pass
           
    def on_index_row_activated(self, widget, path, view_column):
        self.show_note(path)
           
    def edited_cell(self, cell, path, new_text, user_data):
        iter=self.datamodel.get_iter(path)
        path=self.datamodel.get_path(iter)  #path is given to
edited_cell in non-standard format
        parent=self.datamodel.iter_parent(iter)
        parent_path=self.datamodel.get_path(parent)

        #template section
        if parent_path!=self.templates_root:
            templates_iter=self.datamodel.get_iter(self.templates_root)
            templates=[self.datamodel.iter_nth_child(templates_iter, i)
                       for i in
range(self.datamodel.iter_n_children(templates_iter))]
            for iter in templates: #TODO: search subchildren
                template_name = self.datamodel.get_value(iter,0)
                if new_text==template_name:
                    print 'Template name match: '+template_name
                    template_path=self.datamodel.get_path(iter)
                    self.notes[path] =
ZimMindMap.templatechar+self.notes[template_path]
                    self.noteindex.set_cursor(path,
focus_column=self.title_column ,start_editing=True)
                    return True

        if self.notes[path][0]==ZimMindMap.templatechar:
            nota=self.notes[path][1:]
        else:
            nota = new_text
        self.delnote(path)
        self.newnote(new_text, parent, nota)
        self.cellrender.set_property('editable',False)

        self.noteindex.expand_row(parent_path,True)     #not the right
thing, but works
        self.noteindex.set_cursor(path, focus_column=self.title_column
,start_editing=False)
        self.show_note(path)

    def show_note(self, path):
        self.save_note()
        try:
            note_text = self.notes[path]
           
            buffer = self.noteeditor.get_buffer()
            buffer.set_text(note_text)
            self.current_note=path
        except KeyError:
            buffer = self.noteeditor.get_buffer()
            buffer.set_text(repr(path)+' not found')

    def save_note(self):
        if self.current_note:
            buffer = self.noteeditor.get_buffer()
            start, end = buffer.get_bounds()
            self.notes[self.current_note] = buffer.get_text(start, end)

if __name__ == "__main__":
    tareas = ZimMindMap()
    tareas.window.show()
    gtk.main()
      

------------------------------- zimmindmap.glade
-------------------------------

<?xml version="1.0"?>
<interface>
  <requires lib="gtk+" version="2.12"/>
  <!-- interface-naming-policy project-wide -->
  <object class="GtkWindow" id="mainwindow">
    <signal name="destroy" handler="on_mainwindow_destroy"/>
    <signal name="key_release_event"
handler="on_mainwindow_key_release_event"/>
    <child>
      <object class="GtkVBox" id="vbox1">
        <property name="visible">True</property>
        <property name="orientation">vertical</property>
        <child>
          <object class="GtkMenuBar" id="menubar1">
            <property name="visible">True</property>
            <child>
              <object class="GtkMenuItem" id="menuitem1">
                <property name="visible">True</property>
                <property name="label"
translatable="yes">_Archivo</property>
                <property name="use_underline">True</property>
                <child type="submenu">
                  <object class="GtkMenu" id="menu1">
                    <property name="visible">True</property>
                    <child>
                      <object class="GtkImageMenuItem" id="imagemenuitem1">
                        <property name="label">gtk-new</property>
                        <property name="visible">True</property>
                        <property name="use_underline">True</property>
                        <property name="use_stock">True</property>
                      </object>
                    </child>
                    <child>
                      <object class="GtkImageMenuItem" id="imagemenuitem2">
                        <property name="label">gtk-open</property>
                        <property name="visible">True</property>
                        <property name="use_underline">True</property>
                        <property name="use_stock">True</property>
                      </object>
                    </child>
                    <child>
                      <object class="GtkImageMenuItem" id="imagemenuitem3">
                        <property name="label">gtk-save</property>
                        <property name="visible">True</property>
                        <property name="use_underline">True</property>
                        <property name="use_stock">True</property>
                      </object>
                    </child>
                    <child>
                      <object class="GtkImageMenuItem" id="imagemenuitem4">
                        <property name="label">gtk-save-as</property>
                        <property name="visible">True</property>
                        <property name="use_underline">True</property>
                        <property name="use_stock">True</property>
                      </object>
                    </child>
                    <child>
                      <object class="GtkSeparatorMenuItem"
id="separatormenuitem1">
                        <property name="visible">True</property>
                      </object>
                    </child>
                    <child>
                      <object class="GtkImageMenuItem" id="imagemenuitem5">
                        <property name="label">gtk-quit</property>
                        <property name="visible">True</property>
                        <property name="use_underline">True</property>
                        <property name="use_stock">True</property>
                      </object>
                    </child>
                  </object>
                </child>
              </object>
            </child>
            <child>
              <object class="GtkMenuItem" id="menuitem2">
                <property name="visible">True</property>
                <property name="label" translatable="yes">_Editar</property>
                <property name="use_underline">True</property>
                <child type="submenu">
                  <object class="GtkMenu" id="menu2">
                    <property name="visible">True</property>
                    <child>
                      <object class="GtkImageMenuItem" id="imagemenuitem6">
                        <property name="label">gtk-cut</property>
                        <property name="visible">True</property>
                        <property name="use_underline">True</property>
                        <property name="use_stock">True</property>
                      </object>
                    </child>
                    <child>
                      <object class="GtkImageMenuItem" id="imagemenuitem7">
                        <property name="label">gtk-copy</property>
                        <property name="visible">True</property>
                        <property name="use_underline">True</property>
                        <property name="use_stock">True</property>
                      </object>
                    </child>
                    <child>
                      <object class="GtkImageMenuItem" id="imagemenuitem8">
                        <property name="label">gtk-paste</property>
                        <property name="visible">True</property>
                        <property name="use_underline">True</property>
                        <property name="use_stock">True</property>
                      </object>
                    </child>
                    <child>
                      <object class="GtkImageMenuItem" id="imagemenuitem9">
                        <property name="label">gtk-delete</property>
                        <property name="visible">True</property>
                        <property name="use_underline">True</property>
                        <property name="use_stock">True</property>
                      </object>
                    </child>
                  </object>
                </child>
              </object>
            </child>
            <child>
              <object class="GtkMenuItem" id="menuitem3">
                <property name="visible">True</property>
                <property name="label" translatable="yes">_Ver</property>
                <property name="use_underline">True</property>
              </object>
            </child>
            <child>
              <object class="GtkMenuItem" id="menuitem4">
                <property name="visible">True</property>
                <property name="label" translatable="yes">Ay_uda</property>
                <property name="use_underline">True</property>
                <child type="submenu">
                  <object class="GtkMenu" id="menu3">
                    <property name="visible">True</property>
                    <child>
                      <object class="GtkImageMenuItem" id="imagemenuitem10">
                        <property name="label">gtk-about</property>
                        <property name="visible">True</property>
                        <property name="use_underline">True</property>
                        <property name="use_stock">True</property>
                      </object>
                    </child>
                  </object>
                </child>
              </object>
            </child>
          </object>
          <packing>
            <property name="expand">False</property>
            <property name="position">0</property>
          </packing>
        </child>
        <child>
          <object class="GtkHPaned" id="hpane1">
            <property name="visible">True</property>
            <property name="can_focus">True</property>
            <child>
              <object class="GtkScrolledWindow" id="scrolledwindow1">
                <property name="visible">True</property>
                <property name="can_focus">True</property>
                <property name="hscrollbar_policy">automatic</property>
                <property name="vscrollbar_policy">automatic</property>
                <child>
                  <object class="GtkTreeView" id="index">
                    <property name="width_request">200</property>
                    <property name="height_request">300</property>
                    <property name="visible">True</property>
                    <property name="can_focus">True</property>
                    <signal name="key_press_event"
handler="on_index_key_press_event"/>
                    <signal name="cursor_changed"
handler="on_index_cursor_changed"/>
                    <signal name="row_activated"
handler="on_index_row_activated"/>
                  </object>
                </child>
              </object>
              <packing>
                <property name="resize">False</property>
                <property name="shrink">True</property>
              </packing>
            </child>
            <child>
              <object class="GtkTextView" id="noteeditor">
                <property name="width_request">300</property>
                <property name="height_request">300</property>
                <property name="visible">True</property>
                <property name="can_focus">True</property>
              </object>
              <packing>
                <property name="resize">True</property>
                <property name="shrink">True</property>
              </packing>
            </child>
          </object>
          <packing>
            <property name="position">1</property>
          </packing>
        </child>
      </object>
    </child>
  </object>
</interface>

Attachment: zimmindmap.glade
Description: application/glade

import sys
import gtk

class ZimMindMap(object):
    """ mock up of zim to test an idea """
    temptitle = 'Title'
    templatechar = '.'
    
    def __init__ (self):
        """ Class initialiser """
        self.notes={}
        self.current_note = None
        
        self.builder = gtk.Builder()
        self.builder.add_from_file("zimmindmap.glade") 
        
        self.window = self.builder.get_object("mainwindow")
        self.noteeditor = self.builder.get_object("noteeditor")
        self.noteindex = self.builder.get_object("index")

        self.datamodel = gtk.TreeStore(str)

        self.cellrender=gtk.CellRendererText() # renderer para la primera columna
        self.title_column = gtk.TreeViewColumn('Notes')
        self.title_column.pack_start(self.cellrender,True)
        self.title_column.add_attribute(self.cellrender, "text", 0)
        self.noteindex.append_column(self.title_column)

        uno = self.newnote('Hello1')
        dos = self.newnote('Hello2')
        self.newnote('Hello11',uno)
        self.newnote('Hello12',uno)
        self.newnote('Hello21',dos)
        self.newnote('Hello22',dos)
        templates_iter=self.newnote('Templates')
        self.templates_root = self.datamodel.get_path(templates_iter)

        self.noteindex.set_model(self.datamodel)
        self.builder.connect_signals(self)       

    def newnote(self, title, parent=None, texto=None):
        it = self.datamodel.append(parent, (title,))
        path = self.datamodel.get_path(it)
        if not texto:
            texto=title
        self.notes[path] = texto
        return it

    def delnote(self, path):
        iter=self.datamodel.get_iter(path)
        self.datamodel.remove(iter)
        del self.notes[path]

    def on_mainwindow_destroy(self,widget,data=[]):
        gtk.main_quit()

    def on_mainwindow_key_release_event(self,widget,data=[]):
        if data.keyval==32  and (data.state& gtk.gdk.CONTROL_MASK):   #Control+space
            if self.noteeditor.is_focus():
                self.noteindex.grab_focus()
            else:
                self.noteeditor.grab_focus()
            return True
    def on_index_key_press_event(self,widget,data=[]):
        #65361: left, 65362:up, 65363: right, 65364:down, 65293:Enter, 32:space
        if data.keyval==65363:   #right
            current_row,current_column=widget.get_cursor()
            current_iter=self.datamodel.get_iter(current_row)
            widget.expand_row(current_row,False)
            if data.state & gtk.gdk.MOD1_MASK:#Alt+Left
                new_note_iter=self.newnote(ZimMindMap.temptitle, parent=current_iter)
                new_note_path=self.datamodel.get_path(new_note_iter)
#                widget.expand_row(new_note_path,True)  #doesn't work if current_row only has just this child
                widget.expand_row(current_row,True)     #not the right thing, but works
                self.cellrender.set_property('editable',True)
                self.cellrender.connect('edited',self.edited_cell,self.datamodel)
                self.noteindex.set_cursor(new_note_path, focus_column=self.title_column ,start_editing=True)
        elif data.keyval==65364 and (data.state& gtk.gdk.MOD1_MASK):#Alt+down
            current_row,current_column=widget.get_cursor()
            current_iter=self.datamodel.get_iter(current_row)
            parent_iter=self.datamodel.iter_parent(current_iter)
            parent_path=self.datamodel.get_path(parent_iter) if parent_iter else ()
            new_note_iter=self.newnote(ZimMindMap.temptitle, parent=parent_iter)
            new_note_path=self.datamodel.get_path(new_note_iter)
            if parent_path:
                widget.expand_row(parent_path,True)     #not the right thing, but works
            self.cellrender.set_property('editable',True)
            self.cellrender.connect('edited',self.edited_cell,self.datamodel)
            self.noteindex.set_cursor(new_note_path, focus_column=self.title_column ,start_editing=True)
        elif data.keyval==65361:  #left
            current_row,current_column=widget.get_cursor()
            current_iter=self.datamodel.get_iter(current_row)
            widget.collapse_row(current_row)
        elif data.keyval==65293 or data.keyval==32:   #Enter or space
            selection = widget.get_selection()
            model,iter = selection.get_selected()
            path = self.datamodel.get_path(iter)
            self.show_note(path)
            return True

    def on_index_cursor_changed(self,widget,data=None):
        pass
            
    def on_index_row_activated(self, widget, path, view_column):
        self.show_note(path)
            
    def edited_cell(self, cell, path, new_text, user_data):
        iter=self.datamodel.get_iter(path)
        path=self.datamodel.get_path(iter)  #path is given to edited_cell in non-standard format
        parent=self.datamodel.iter_parent(iter)
        parent_path=self.datamodel.get_path(parent)

        #template section
        if parent_path!=self.templates_root:
            templates_iter=self.datamodel.get_iter(self.templates_root)
            templates=[self.datamodel.iter_nth_child(templates_iter, i)
                       for i in range(self.datamodel.iter_n_children(templates_iter))]
            for iter in templates: #TODO: search subchildren
                template_name = self.datamodel.get_value(iter,0)
                if new_text==template_name:
                    print 'Template name match: '+template_name
                    template_path=self.datamodel.get_path(iter)
                    self.notes[path] = ZimMindMap.templatechar+self.notes[template_path]
                    self.noteindex.set_cursor(path, focus_column=self.title_column ,start_editing=True)
                    return True

        if self.notes[path][0]==ZimMindMap.templatechar:
            nota=self.notes[path][1:]
        else:
            nota = new_text
        self.delnote(path)
        self.newnote(new_text, parent, nota)
        self.cellrender.set_property('editable',False)

        self.noteindex.expand_row(parent_path,True)     #not the right thing, but works
        self.noteindex.set_cursor(path, focus_column=self.title_column ,start_editing=False)
        self.show_note(path)

    def show_note(self, path):
        self.save_note()
        try:
            note_text = self.notes[path]
            
            buffer = self.noteeditor.get_buffer()
            buffer.set_text(note_text)
            self.current_note=path
        except KeyError:
            buffer = self.noteeditor.get_buffer()
            buffer.set_text(repr(path)+' not found')

    def save_note(self):
        if self.current_note:
            buffer = self.noteeditor.get_buffer()
            start, end = buffer.get_bounds()
            self.notes[self.current_note] = buffer.get_text(start, end)

if __name__ == "__main__":
    tareas = ZimMindMap()
    tareas.window.show()
    gtk.main()
       

Follow ups