This is really a proof of concept but seems to work well in the 10 minutes
I've used it :-). I hope it's of interest.
I was inspired by Ville's stickynote plugin since I have always wanted to
have Leo notes with rich text (a little more than in Ville's
proof-of-concept). So I have modified Ville's plugin by adding a command
"stickynoteplus".
What this does is support almost the complete set of markdown markup (if
that's not a confusing phrase). So if you are in a note and do Alt-X
'stickynoteplus' you will see a new window launched with whatever text was
in the Leo note for that node but it will now be displayed in rich text. If
you right click you will see that you can do the following:
- Bold
- Italic
- Monospaced*
- Anchor (external link)
- Code block*
- Numbered List
- Header (H1, H2, H3)
- Remove All Formatting
- Save (you need to explicitly save what you do -- the focusin/focusout was
a problem for my implementation)
As a bonus, if you paste a URL into the note, it (should) recognize it's a
URL and make it a link that actually works
Note that this has one external dependency and that is python-markdown.
It's at http://www.freewisdom.org/projects/python-markdown/. There is a
windows installer and it's available from PyPI. If you're on Ubuntu, it's
in universe. For the plugin, I wrote the QTextEdit-to-markdown code but
python-markdown works well for taking the markdown in the Leo node and
transforming it into HTML for loading into the QTextEdit window.
Note that you do not have to understand markdown at all to use this. You
just highlight some text and right-click in the stickynoteplus window and
mark up the content to your heart's content. However, the beauty of this
(and this is really the key point) is what is saved to the Leo node is easy
to read markdown text and not HTML and especially not QTextEdit's verbose,
quirky implementation of HTML. And if you feel like editing the markdown,
you do that just like you would work with plain text in any Leo node and the
next time you launch the stickynoteplus, it will reflect whatever changes
you made.
This is barely tested so you're warned but I think the concept of rich text
editing and display in Leo is important and I also think the format to save
that rich text should be a text format that can be directly edited if you
feel like it and that is readable as plain text. Restructured Text would
also have been possible but it's more complex and seems like overkill when
dealing with an individual Leo node note.
The plugin is called stickynotes_plus and is attached. (Let me know if it
comes through unscathed.) You enable it like any plugin and invoke it as
'stickynotesplus' (without any underscore).
Remember, the only way to edit the rich text is through the right-click
context menu and you need to use the same context menu to save your changes.
Some simple things like shortcuts would obviously be helpful and I am sure
there are other changes that would improve it.
Please let me know whether this is worth pursuing.
Steve
* Small note -- if you're on some flavor of Linux and don't have some New
Courier font equivalent (like contained in the Liberation fonts) then the
code blocks will not be fixed pitch.
--
You received this message because you are subscribed to the Google Groups
"leo-editor" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to
[email protected].
For more options, visit this group at
http://groups.google.com/group/leo-editor?hl=en.
#...@+leo-ver=4-thin
#...@+node:slzatz.20100102152658.2800:@thin /home/slzatz/leo-editor/leo/plugins/stickynotes_plus.py
#@<< docstring >>
#...@+node:vivainio2.20091008133028.5821:<< docstring >>
''' Simple "sticky notes" feature (popout editors)
alt-x stickynote to pop out current node as a note
'''
#...@-node:vivainio2.20091008133028.5821:<< docstring >>
#...@nl
__version__ = '0.0'
#@<< version history >>
#...@+node:vivainio2.20091008133028.5822:<< version history >>
#@@killcolor
#...@+at
#
# Put notes about each version here.
#...@-at
#...@nonl
#...@-node:vivainio2.20091008133028.5822:<< version history >>
#...@nl
#@<< imports >>
#...@+node:vivainio2.20091008133028.5823:<< imports >>
import leo.core.leoGlobals as g
from leo.core import leoPlugins
# Whatever other imports your plugins uses.
g.assertUi('qt')
import sys
import webbrowser
import markdown
from PyQt4.QtCore import (QSize, QString, QVariant, Qt, SIGNAL,QTimer)
from PyQt4.QtGui import (QAction, QApplication, QColor, QFont,
QFontMetrics, QIcon, QKeySequence, QMenu, QPixmap, QTextCursor,
QTextCharFormat, QTextBlockFormat, QTextListFormat,QTextEdit,QPlainTextEdit)
#...@nonl
#...@-node:vivainio2.20091008133028.5823:<< imports >>
#...@nl
#...@+others
#...@+node:vivainio2.20091008140054.14555:styling
stickynote_stylesheet = """
/* The body pane */
QPlainTextEdit {
background-color: #fdf5f5; /* A kind of pink. */
selection-color: white;
selection-background-color: lightgrey;
font-family: DejaVu Sans Mono;
/* font-family: Courier New; */
font-size: 12px;
font-weight: normal; /* normal,bold,100,..,900 */
font-style: normal; /* normal,italic,oblique */
}
"""
def decorate_window(w):
w.setStyleSheet(stickynote_stylesheet)
w.setWindowIcon(QIcon(g.app.leoDir + "/Icons/leoapp32.png"))
w.resize(600, 300)
#...@-node:vivainio2.20091008140054.14555:styling
#...@+node:vivainio2.20091008133028.5824:init
def init ():
ok = True
if ok:
#leoPlugins.registerHandler('start2',onStart2)
g.plugin_signon(__name__)
g.app.stickynotes = {}
return ok
#...@-node:vivainio2.20091008133028.5824:init
#...@+node:ville.20091008210853.7616:class FocusingPlainTextEdit
class FocusingPlaintextEdit(QPlainTextEdit):
def __init__(self, focusin, focusout):
QPlainTextEdit.__init__(self)
self.focusin = focusin
self.focusout = focusout
def focusOutEvent (self, event):
#print "focus out"
self.focusout()
def focusInEvent (self, event):
self.focusin()
def closeEvent(self, event):
event.accept()
self.focusout()
#...@-node:ville.20091008210853.7616:class FocusingPlainTextEdit
#...@+node:ville.20091023181249.5264:class SimpleRichText
class SimpleRichText(QTextEdit):
def __init__(self, focusin, focusout):
QTextEdit.__init__(self)
self.focusin = focusin
self.focusout = focusout
self.createActions()
#self.setContextMenuPolicy(QtCore.Qt.ActionsContextMenu)
def focusOutEvent ( self, event ):
#print "focus out"
self.focusout()
def focusInEvent ( self, event ):
self.focusin()
def closeEvent(self, event):
event.accept()
def createActions(self):
self.boldAct = QAction(self.tr("&Bold"), self)
self.boldAct.setCheckable(True)
self.boldAct.setShortcut(self.tr("Ctrl+B"))
self.boldAct.setStatusTip(self.tr("Make the text bold"))
self.connect(self.boldAct, SIGNAL("triggered()"), self.setBold)
self.addAction(self.boldAct)
boldFont = self.boldAct.font()
boldFont.setBold(True)
self.boldAct.setFont(boldFont)
self.italicAct = QAction(self.tr("&Italic"), self)
self.italicAct.setCheckable(True)
self.italicAct.setShortcut(self.tr("Ctrl+I"))
self.italicAct.setStatusTip(self.tr("Make the text italic"))
self.connect(self.italicAct, SIGNAL("triggered()"), self.setItalic)
self.addAction(self.italicAct)
def setBold(self):
format = QTextCharFormat()
if self.boldAct.isChecked():
weight = QFont.Bold
else:
weight = QFont.Normal
format.setFontWeight(weight)
self.setFormat(format)
def setItalic(self):
format = QTextCharFormat()
#format.setFontItalic(self.__italic.isChecked())
format.setFontItalic(self.italicAct.isChecked())
self.setFormat(format)
def setUnderline(self):
format = QTextCharFormat()
format.setFontUnderline(self.__underline.isChecked())
self.setFormat(format)
def setFormat(self, format):
self.textCursor().mergeCharFormat(format)
self.mergeCurrentCharFormat(format)
def bold(self):
print("bold")
def italic(self):
print("italic")
#...@-node:ville.20091023181249.5264:class SimpleRichText
#...@+node:slzatz.20100103053959.2868:class notetextedit
class notetextedit(QTextEdit):
(Bold, Italic, Pre, List, Remove,
Plain, Code, H1, H2, H3, Anchor,Save) = range(12)
#@ @+others
#...@+node:slzatz.20100103053959.2869:__init__
def __init__(self, get_markdown, save, parent=None):
super(notetextedit, self).__init__(parent)
self.save = save
self.setLineWrapMode(QTextEdit.WidgetWidth)
self.setTabChangesFocus(True)
self.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded)
self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
self.setMinimumWidth(300)
self.setMouseTracking(True)
font = QFont()
font.setPointSize(10)
font.setFamily("helvetica")
document = self.document()
document.setDefaultFont(font)
self.font = font
document.setDefaultStyleSheet("pre{margin-top:0px; margin-bottom:0px} li{margin-top:0px; margin-bottom:0px}")
QTimer.singleShot(0, get_markdown)
#...@-node:slzatz.20100103053959.2869:__init__
#...@+node:slzatz.20100103055234.2714:focusOutEvent
def focusOutEvent__(self, event):
#print "focus out"
self.focusout()
#...@-node:slzatz.20100103055234.2714:focusOutEvent
#...@+node:slzatz.20100103055234.2715:focusInEvent
def focusInEvent__(self, event):
self.focusin()
#...@-node:slzatz.20100103055234.2715:focusInEvent
#...@+node:slzatz.20100103053959.2870:toggleItalic
def toggleItalic(self):
if self.which_header():
return
#self.setFontItalic(not self.fontItalic())
italic = self.fontItalic()
cursor = self.textCursor()
char_format = QTextCharFormat()
char_format.setFont(self.font)
char_format.setFontItalic(not italic)
cursor.setCharFormat(char_format)
#...@-node:slzatz.20100103053959.2870:toggleItalic
#...@+node:slzatz.20100103053959.2871:toggleUnderline
def toggleUnderline(self):
#not in use, markdown doesn't support
self.setFontUnderline(not self.fontUnderline())
#...@-node:slzatz.20100103053959.2871:toggleUnderline
#...@+node:slzatz.20100103053959.2872:make_plain_text
def make_plain_text(self):
cursor = self.textCursor()
char_format = QTextCharFormat()
char_format.setFont(self.font)
cursor.setCharFormat(char_format)
block_format = QTextBlockFormat()
block_format.setNonBreakableLines(False)
cursor.setBlockFormat(block_format)
#...@-node:slzatz.20100103053959.2872:make_plain_text
#...@+node:slzatz.20100103053959.2873:make_pre_block
def make_pre_block(self):
cursor = self.textCursor()
block_format = cursor.blockFormat()
if block_format.nonBreakableLines():
block_format.setNonBreakableLines(False)
cursor.setBlockFormat(block_format)
char_format = QTextCharFormat()
char_format.setFontFixedPitch(False)
cursor.setCharFormat(char_format)
else:
block_format.setNonBreakableLines(True)
cursor.setBlockFormat(block_format)
char_format = QTextCharFormat()
char_format.setFontFixedPitch(True)
cursor.setCharFormat(char_format)
#...@-node:slzatz.20100103053959.2873:make_pre_block
#...@+node:slzatz.20100103053959.2874:toggleBold
def toggleBold(self):
#self.setFontWeight(QFont.Normal if self.fontWeight() > QFont.Normal else QFont.Bold)
if self.which_header():
return
bold = self.fontWeight() > QFont.Normal
cursor = self.textCursor()
char_format = QTextCharFormat()
char_format.setFont(self.font)
char_format.setFontWeight(QFont.Normal if bold else QFont.Bold)
cursor.setCharFormat(char_format)
#...@-node:slzatz.20100103053959.2874:toggleBold
#...@+node:slzatz.20100103053959.2875:toggleCode
def toggleCode(self):
if self.which_header():
return
cursor = self.textCursor()
#if not cursor.hasSelection():
# return
char_format = cursor.charFormat()
if char_format.fontFixedPitch():
# didn't do exhaustive testing but appear to need both statements
char_format.setFontFixedPitch(False)
char_format.setFontFamily("helvetica")
else:
char_format.setFontFixedPitch(True)
char_format.setFontFamily("courier")
char_format.setFontItalic(False)
char_format.setFontWeight(QFont.Normal)
cursor.setCharFormat(char_format)
#The below also works but seems a little more kludgy
#text = unicode(cursor.selectedText()) # need unicode for if below
#text = '<code>{0}</code>'.format(text)
#cursor.removeSelectedText() #cursor.deleteChar()
#cursor.insertHtml(text) # also self.insertHtml should work
#...@-node:slzatz.20100103053959.2875:toggleCode
#...@+node:slzatz.20100103053959.2876:create_anchor
def create_anchor(self):
cursor = self.textCursor()
if not cursor.hasSelection():
return
text = unicode(cursor.selectedText()) # need unicode for if below
if text.startswith('http://'):
text = '<a href="{0}">{1}</a> '.format(text, text[7:])
else:
text = '<a href="http://{0}">{0}</a> '.format(text)
# the below works but doesn't pick up highlighting of an anchor - would have to do the underlining and blue color
#format = QTextCharFormat()
#format.setAnchor(True)
#format.setAnchorHref(text)
#cursor.setCharFormat(format)
##self.setTextCursor(cursor)
#this also works and generates highlighting
cursor.deleteChar()
cursor.insertHtml(text) # also self.insertHtml should work
#...@-node:slzatz.20100103053959.2876:create_anchor
#...@+node:slzatz.20100103053959.2877:create_list
def create_list(self):
cursor = self.textCursor()
if not cursor.hasSelection():
return
cursor.createList(QTextListFormat.ListDecimal)
#...@-node:slzatz.20100103053959.2877:create_list
#...@+node:slzatz.20100103053959.2878:make_heading
def make_heading(self, heading):
# not finished
cursor = self.textCursor()
cursor.select(QTextCursor.BlockUnderCursor) #QTextCursor.LineUnderCursor
char_format = QTextCharFormat()
#font = self.font this is a problem because it changes self.font gets changed below
font = QFont()
font.setFamily("helvetica")
font.setPointSize({1:20, 2:15, 3:12}[heading])
font.setBold(True)
char_format.setFont(font)
cursor.setCharFormat(char_format)
#...@-node:slzatz.20100103053959.2878:make_heading
#...@+node:slzatz.20100103053959.2879:sizeHint
def sizeHint(self): # this makes the text box taller when launched than if I don't have it
return QSize(self.document().idealWidth() + 5, self.maximumHeight())
#...@-node:slzatz.20100103053959.2879:sizeHint
#...@+node:slzatz.20100103053959.2880:contextMenuEvent
def contextMenuEvent(self, event): # this catches the context menu right click
self.textEffectMenu()
#...@-node:slzatz.20100103053959.2880:contextMenuEvent
#...@+node:slzatz.20100103053959.2881:keyPressEvent__
def keyPressEvent__(self, event):
# needed because text edit is not going to recognize short cuts because will do something with control key
# not needed if have global shortcuts
if event.modifiers() & Qt.ControlModifier:
handled = False
if event.key() == Qt.Key_A:
self.create_anchor()
handled = True
elif event.key() == Qt.Key_B:
self.toggleBold()
handled = True
elif event.key() == Qt.Key_I:
self.toggleItalic()
handled = True
#elif event.key() == Qt.Key_K:
#self.colorMenu()
#handled = True
elif event.key() == Qt.Key_M:
self.textEffectMenu()
handled = True
elif event.key() == Qt.Key_P:
self.make_plain_text()
handled = True
elif event.key() == Qt.Key_Z:
self.make_pre_block()
handled = True
elif event.key() == Qt.Key_U:
self.toggleUnderline()
handled = True
if handled:
event.accept()
return
QTextEdit.keyPressEvent(self, event)
#...@-node:slzatz.20100103053959.2881:keyPressEvent__
#...@+node:slzatz.20100103053959.2882:fontFixedPitch
def fontFixedPitch(self):
cursor = self.textCursor()
format = cursor.charFormat()
return format.fontFixedPitch()
#...@-node:slzatz.20100103053959.2882:fontFixedPitch
#...@+node:slzatz.20100103053959.2883:which_header
def which_header(self):
cursor = self.textCursor()
char_format = cursor.charFormat()
ps = char_format.font().pointSize()
return {20:'H1', 15:'H2', 12:'H3'}.get(ps)
#...@-node:slzatz.20100103053959.2883:which_header
#...@+node:slzatz.20100103053959.2884:textEffectMenu
def textEffectMenu(self):
format = self.currentCharFormat()
cursor = self.textCursor()
blockformat = cursor.blockFormat()
menu = QMenu("Text Effect")
for text, shortcut, data, checked in (
("&Bold", "Ctrl+B", notetextedit.Bold,
self.fontWeight() > QFont.Normal),
("&Italic", "Ctrl+I", notetextedit.Italic,
self.fontItalic()),
("&Monospaced", None, notetextedit.Code,
self.fontFixedPitch())
):
action = menu.addAction(text, self.setTextEffect)
#if shortcut is not None:
#action.setShortcut(QKeySequence(shortcut)) # becau
action.setData(QVariant(data))
action.setCheckable(True)
action.setChecked(checked)
menu.addSeparator()
action = menu.addAction("Anchor", self.setTextEffect)
action.setData(notetextedit.Anchor)
action = menu.addAction("Code Block", self.setTextEffect)
action.setData(notetextedit.Pre)
action = menu.addAction("Numbered List", self.setTextEffect)
action.setData(notetextedit.List)
header_menu = QMenu("Header")
action = header_menu.addAction('H1', self.setTextEffect)
action.setData(notetextedit.H1)
action.setCheckable(True)
action.setChecked(self.which_header()=='H1')
action = header_menu.addAction('H2', self.setTextEffect)
action.setData(notetextedit.H2)
action.setCheckable(True)
action.setChecked(self.which_header()=='H2')
action = header_menu.addAction('H3', self.setTextEffect)
action.setData(notetextedit.H3)
action.setCheckable(True)
action.setChecked(self.which_header()=='H3')
action = menu.addAction("Remove All Formatting", self.setTextEffect)
action.setData(notetextedit.Remove)
menu.addMenu(header_menu)
menu.addSeparator()
action = menu.addAction("Save", self.setTextEffect)
action.setData(notetextedit.Save)
self.ensureCursorVisible()
menu.exec_(self.viewport().mapToGlobal(self.cursorRect().center()))
#...@-node:slzatz.20100103053959.2884:textEffectMenu
#...@+node:slzatz.20100103053959.2885:setTextEffect
def setTextEffect(self):
action = self.sender()
if action is not None and isinstance(action, QAction):
what = action.data().toInt()[0]
if what == notetextedit.Bold:
self.toggleBold()
elif what == notetextedit.Italic:
self.toggleItalic()
elif what == notetextedit.Code:
self.toggleCode()
elif what == notetextedit.Anchor:
self.create_anchor()
elif what == notetextedit.Pre:
self.make_pre_block()
elif what == notetextedit.Remove:
self.make_plain_text()
elif what == notetextedit.List:
self.create_list()
elif what == notetextedit.H1:
self.make_heading(1)
elif what == notetextedit.H2:
self.make_heading(2)
elif what == notetextedit.H3:
self.make_heading(3)
elif what == notetextedit.Save:
self.save()
#...@-node:slzatz.20100103053959.2885:setTextEffect
#...@+node:slzatz.20100103053959.2886:mouseMoveEvent
def mouseMoveEvent(self, event):
#print "mouseMoveEvent"
pos = event.pos()
anch = self.anchorAt(pos)
self.viewport().setCursor(Qt.PointingHandCursor if anch else Qt.IBeamCursor)
QTextEdit.mouseMoveEvent(self, event) #? recursion
#...@-node:slzatz.20100103053959.2886:mouseMoveEvent
#...@+node:slzatz.20100103053959.2887:mouseReleaseEvent
def mouseReleaseEvent(self, event):
#print("mouseReleaseEvent")
pos = event.pos()
url = unicode(self.anchorAt(pos))
if url:
if not url.startswith('http://'): #linux seems to need this
url = 'http://{0}'.format(url)
webbrowser.open(unicode(x), new=2, autoraise=True)
else:
QTextEdit.mouseReleaseEvent(self, event)
#...@-node:slzatz.20100103053959.2887:mouseReleaseEvent
#...@+node:slzatz.20100103053959.2888:insertFromMimeData
def insertFromMimeData(self, source):
# not sure really necessary since it actually appears to paste URLs correctly
# I am stripping the http
print "Paste"
text = unicode(source.text())
if len(text.split())==1 and (text.startswith('http://') or 'www' in text or '.com' in text or '.html' in text):
if text.startswith('http://'):
text = '<a href="{0}">{1}</a> '.format(text, text[7:])
else:
text = '<a href="http://{0}">{0}</a> '.format(text)
self.insertHtml(text)
else:
QTextEdit.insertFromMimeData(self, source)
#...@-node:slzatz.20100103053959.2888:insertFromMimeData
#...@+node:slzatz.20100103053959.2890:toMarkdown
def toMarkdown(self):
references = ''
i = 1
doc = QString() # the full document
block = self.document().begin() # block is like a para; text fragment is sequence of same char format
while block.isValid():
#print "block=",block.text()
if block.blockFormat().nonBreakableLines():
doc += ' '+block.text()+'\n'
#elif block.textList():
#textList = block.textList()
#print block.textList().count()
#print unicode(block.textList().itemText(block))
#print block.textList().itemNumber(block)
#print block.textList().item(block.textList().itemNumber(block)).text()
#doc += textList.itemText(block) + ' ' + textList.item(textList.itemNumber(block)).text() + '\n\n'
else:
if block.textList():
doc += ' '+block.textList().itemText(block) + ' '
para = QString()
iterator = block.begin()
while iterator != block.end():
fragment = iterator.fragment()
if fragment.isValid():
char_format = fragment.charFormat()
text = unicode(Qt.escape(fragment.text())) # turns chars like < into entities <
font_size = char_format.font().pointSize()
# a fragment can only be an anchor, italics or bold
if char_format.isAnchor():
ref = text if text.startswith('http://') else 'http://{0}'.format(text)
# too lazy right now to check if URL has already been referenced but should
references += " [{0}]: {1}\n".format(i,ref)
text = "[{0}][{1}]".format(text,i)
i+=1
elif font_size > 10:
if font_size > 15:
text = '#{0}'.format(text)
elif font_size > 12:
text = '##{0}'.format(text)
else:
text = '###{0}'.format(text)
elif char_format.fontFixedPitch(): #or format.fontFamily=='courier':
text = QString("`%1`").arg(text)
elif char_format.fontItalic():
text = QString("*%1*").arg(text)
elif char_format.fontWeight() > QFont.Normal: #font-weight:600; same as for an H1; H1 font-size:xx-large; H1 20; H2 15 H3 12
text = QString("**%1**").arg(text)
para += text
iterator += 1
doc += para+'\n\n'
block = block.next()
return doc+references
#...@-node:slzatz.20100103053959.2890:toMarkdown
#...@-others
#...@-node:slzatz.20100103053959.2868:class notetextedit
#...@+node:vivainio2.20091008133028.5825:g.command('stickynote')
@g.command('stickynote')
def stickynote_f(event):
""" Launch editable 'sticky note' for the node """
c= event['c']
p = c.p
v = p.v
def focusin():
#print "focus in"
if v is c.p.v:
nf.setPlainText(v.b)
nf.setWindowTitle(p.h)
nf.dirty = False
def focusout():
#print "focus out"
if not nf.dirty:
return
v.b = nf.toPlainText()
v.setDirty()
nf.dirty = False
p = c.p
if p.v is v:
c.selectPosition(c.p)
nf = FocusingPlaintextEdit(focusin, focusout)
nf.dirty = False
decorate_window(nf)
nf.setWindowTitle(p.h)
nf.setPlainText(p.b)
p.setDirty()
def textchanged_cb():
nf.dirty = True
nf.connect(nf,
SIGNAL("textChanged()"),textchanged_cb)
nf.show()
g.app.stickynotes[p.gnx] = nf
#...@-node:vivainio2.20091008133028.5825:g.command('stickynote')
#...@+node:ville.20091023181249.5266:g.command('stickynoter')
@g.command('stickynoter')
def stickynoter_f(event):
""" Launch editable 'sticky note' for the node """
c= event['c']
p = c.p
v = p.v
def focusin():
print("focus in")
if v is c.p.v:
nf.setHtml(v.b)
nf.setWindowTitle(p.h)
nf.dirty = False
def focusout():
print("focus out")
if not nf.dirty:
return
v.b = nf.toHtml()
v.setDirty()
nf.dirty = False
p = c.p
if p.v is v:
c.selectPosition(c.p)
nf = LessSimpleRichText(focusin, focusout)
nf.dirty = False
decorate_window(nf)
nf.setWindowTitle(p.h)
nf.setHtml(p.b)
p.setDirty()
def textchanged_cb():
nf.dirty = True
nf.connect(nf,
SIGNAL("textChanged()"),textchanged_cb)
nf.show()
g.app.stickynotes[p.gnx] = nf
#...@-node:ville.20091023181249.5266:g.command('stickynoter')
#...@+node:slzatz.20100103053959.2843:g.command('stickynoteplus')
@g.command('stickynoteplus')
def stickynoter_f(event):
""" Launch editable 'sticky note' for the node """
c= event['c']
p = c.p
v = p.v
def get_markdown(): #focusin():
print("focus in")
if v is c.p.v:
nf.setHtml(markdown.markdown(v.b))
nf.setWindowTitle(p.h)
nf.dirty = False
def save(): #focusout():
print("focus out")
if not nf.dirty:
return
v.b = nf.toMarkdown()
v.setDirty()
nf.dirty = False
p = c.p
if p.v is v:
c.selectPosition(c.p)
nf = notetextedit(get_markdown, save)
nf.dirty = False
decorate_window(nf)
nf.setWindowTitle(p.h)
nf.setHtml(p.b)
p.setDirty()
def textchanged_cb():
nf.dirty = True
nf.connect(nf,
SIGNAL("textChanged()"),textchanged_cb)
nf.show()
g.app.stickynotes[p.gnx] = nf
#...@-node:slzatz.20100103053959.2843:g.command('stickynoteplus')
#...@-others
#...@nonl
#...@-node:slzatz.20100102152658.2800:@thin /home/slzatz/leo-editor/leo/plugins/stickynotes_plus.py
#...@-leo