diff --git a/FreePlaneGTD.iml b/FreePlaneGTD.iml new file mode 100644 index 0000000..5f0e0ab --- /dev/null +++ b/FreePlaneGTD.iml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/doc/GTD with Freeplane.html b/doc/GTD with Freeplane.html index b458e4f..efd4db1 100644 --- a/doc/GTD with Freeplane.html +++ b/doc/GTD with Freeplane.html @@ -63,7 +63,7 @@ ## Install Freeplane -Download and install [Freeplane](http://freeplane.sourceforge.net) +Download and install [Freeplane](http://freeplane.sourceforge.net) for your computer. ## Install the add-on diff --git a/harness/src/FreePlaneGTD/Harness.groovy b/harness/src/FreePlaneGTD/Harness.groovy new file mode 100644 index 0000000..b3cb660 --- /dev/null +++ b/harness/src/FreePlaneGTD/Harness.groovy @@ -0,0 +1,90 @@ +package FreePlaneGTD + +import freeeplaneHarness.MyController +import freeplaneGTD.ReportModel +import freeplaneGTD.ReportWindow +import groovy.swing.SwingBuilder +import org.freeplane.core.resources.ResourceBundles +import org.freeplane.features.mode.Controller +import org.freeplane.main.application.ApplicationResourceController +import org.freeplane.plugin.script.FreeplaneScriptBaseClass +import org.freeplane.plugin.script.proxy.Proxy +import org.knopflerfish.framework.FrameworkContext +import org.knopflerfish.framework.ServiceURLStreamHandlerFactory + +import javax.swing.* +import java.awt.* +import java.awt.event.ActionEvent + +/** + * Created by gpapp on 2017.05.28.. + */ +class Harness implements Runnable { + private static final String PROPERTY_FILE = "harness/keys.properties" + + @Override + void run() { + def config = new FreeplaneScriptBaseClass.ConfigProperties() + Proxy.Map map + + JFrame myFrame + SwingBuilder.edtBuilder { + myFrame = frame(title: 'FreePlaneGTD.Harness', + defaultCloseOperation: JFrame.EXIT_ON_CLOSE) { + borderLayout() + button(name: 'toolbar', constraints: BorderLayout.NORTH) + button( + constraints: BorderLayout.SOUTH, + text: 'Refresh', + action: + new AbstractAction() { + @Override + void actionPerformed(ActionEvent e) { + Controller currentController = Controller.currentController + ReportWindow reportWindow = currentController.getExtension(ReportWindow.class) + if (!reportWindow) { + reportWindow = new ReportWindow() + currentController.addExtension(ReportWindow.class, reportWindow) + } + reportWindow.show(currentController, config) + reportWindow.refresh(map.root) + } + } + ) + } + } + + myFrame.visible = true + myFrame.setLocation(10, 10) + myFrame.setSize(100, 100) + + def resourceController = new ApplicationResourceController() + Controller.currentController = new MyController(resourceController, myFrame) + ((ResourceBundles) resourceController.resources). + addResources("hu", new URL("file:src/zips/translations/freeplaneGTD_en.properties")) + + ServiceURLStreamHandlerFactory streamHandlerFactory = new ServiceURLStreamHandlerFactory() + URL.setURLStreamHandlerFactory(streamHandlerFactory) + streamHandlerFactory.addFramework(new FrameworkContext([ + "org.osgi.framework.security": "", + "org.osgi.framework.storage" : "/usr/share/freeplane/fwdir"])) + + + map = Controller.currentController.newMap() + addNode(map, "ID__1", "*test task 1") + addNode(map, "ID__2", "*test task 2 {2017-06-19}") + addNode(map, "ID__3", "*test task 3 #3 {2017-06-19} @Context1 @Context2") + + + config.properties.put(ReportWindow.FREEPLANE_GTD_DEFAULT_VIEW, ReportModel.VIEW.WHEN.toString()) + config.properties.put(ReportWindow.FREEPLANE_GTD_REMEMBER_LAST_POSITION, Boolean.TRUE) + + + } + + private static void addNode(Proxy.Map map, String id, String text) { + Proxy.Node child = map.root.createChild() + child.text = text + } + +} diff --git a/harness/src/freeeplaneHarness/MyController.groovy b/harness/src/freeeplaneHarness/MyController.groovy index c463005..da437e3 100644 --- a/harness/src/freeeplaneHarness/MyController.groovy +++ b/harness/src/freeeplaneHarness/MyController.groovy @@ -52,6 +52,7 @@ import org.freeplane.view.swing.map.MapViewController import javax.swing.* import java.awt.dnd.DragGestureListener import java.awt.dnd.DropTargetListener +import java.awt.event.ActionEvent import java.awt.event.KeyListener import java.awt.event.MouseWheelListener @@ -442,4 +443,9 @@ class MyController extends Controller implements Proxy.Controller { void export(Proxy.Map map, File file, String s, boolean b) { } + + @Override + void quit(ActionEvent actionEvent) { + System.exit(0) + } } diff --git a/lib/lib.iml b/lib/lib.iml new file mode 100644 index 0000000..e19656f --- /dev/null +++ b/lib/lib.iml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/zips/lib/freeplaneGTD/ClipBoardUtil.groovy b/lib/src/freeplaneGTD/ClipBoardUtil.groovy similarity index 100% rename from src/zips/lib/freeplaneGTD/ClipBoardUtil.groovy rename to lib/src/freeplaneGTD/ClipBoardUtil.groovy diff --git a/src/zips/lib/freeplaneGTD/DateUtil.groovy b/lib/src/freeplaneGTD/DateUtil.groovy similarity index 100% rename from src/zips/lib/freeplaneGTD/DateUtil.groovy rename to lib/src/freeplaneGTD/DateUtil.groovy diff --git a/src/zips/lib/freeplaneGTD/GTDMapReader.groovy b/lib/src/freeplaneGTD/GTDMapReader.groovy similarity index 100% rename from src/zips/lib/freeplaneGTD/GTDMapReader.groovy rename to lib/src/freeplaneGTD/GTDMapReader.groovy diff --git a/lib/src/freeplaneGTD/JSHandler.groovy b/lib/src/freeplaneGTD/JSHandler.groovy new file mode 100644 index 0000000..7dac596 --- /dev/null +++ b/lib/src/freeplaneGTD/JSHandler.groovy @@ -0,0 +1,145 @@ +package freeplaneGTD + +import org.freeplane.core.ui.components.UITools +import org.freeplane.core.util.TextUtils +import org.freeplane.features.clipboard.ClipboardController +import org.freeplane.features.mode.Controller +import org.freeplane.plugin.script.ScriptContext +import org.freeplane.plugin.script.proxy.Proxy +import org.freeplane.plugin.script.proxy.ProxyFactory +import org.freeplane.plugin.script.proxy.ScriptUtils + +import javax.swing.* +import java.awt.* +import java.util.List +import java.util.logging.Level +import java.util.logging.Logger + +class JSHandler { + private final ReportModel report + private final ReportWindow target + + JSHandler(ReportModel report, ReportWindow target) { + this.target = target + this.report = report + } + + void toggleDone(String linkNodeID) { + try { + def nodesFound = ScriptUtils.c().find { it.id == linkNodeID } + + if (nodesFound[0] != null) { + def node = nodesFound[0] + if (node.icons.contains(report.mapReader.iconDone)) { + node.icons.remove(report.mapReader.iconDone) + } else { + node.icons.add(report.mapReader.iconDone) + } + target.refreshContent() + } else { + UITools.informationMessage("Cannot find node to mark as done") + } + } catch (Exception e) { + System.err.println(e) + } + } + + void followLink(String linkNodeID) { + try { + def nodesFound = ScriptUtils.c().find { it.id == linkNodeID } + + if (nodesFound[0] != null) { + switchToMainWindow() + if (target.autoFoldMap) { + foldToTop(nodesFound[0]) + } + unfoldBranch(nodesFound[0]) + ScriptUtils.c().centerOnNode(nodesFound[0]) + ScriptUtils.c().select(nodesFound[0]) + } else { + UITools.informationMessage("Next Action not found in mind map. Refresh Next Action list") + } + } catch (Exception e) { + Logger.anonymousLogger.log(Level.SEVERE, e.message, e) + } + } + + void copyToClipboard(int pos) { + try { + Map feeder + ClipboardController clip = ClipboardController.controller + switch (target.selectedView) { + case ReportModel.VIEW.PROJECT: feeder = [type: 'project', groups: [report.projectList()['groups'][pos]]]; break + case ReportModel.VIEW.WHO: feeder = [type: 'who', groups: [report.delegateList()['groups'][pos]]]; break + case ReportModel.VIEW.CONTEXT: feeder = [type: 'context', groups: [report.contextList()['groups'][pos]]]; break + case ReportModel.VIEW.WHEN: feeder = [type: 'when', groups: [report.timelineList()['groups'][pos]]]; break + default: throw new UnsupportedOperationException("Invalid selection pane: " + target.selectedView) + } + clip.clipboardContents = ClipBoardUtil.createTransferable(feeder, report.mapReader, target.showNotes) + UITools.informationMessage(TextUtils.getText('freeplaneGTD.message.copy_ok')) + } catch (Exception e) { + Logger.anonymousLogger.log(Level.SEVERE, e.message, e) + } + } + + void selectOnMap(int pos) { + try { + List list + switch (target.selectedView) { + case ReportModel.VIEW.PROJECT: list = (List) report.projectList()['groups'][pos]['items']; break + case ReportModel.VIEW.WHO: list = (List) report.delegateList()['groups'][pos]['items']; break + case ReportModel.VIEW.CONTEXT: list = (List) report.contextList()['groups'][pos]['items']; break + case ReportModel.VIEW.WHEN: list = (List) report.timelineList()['groups'][pos]['items']; break + default: throw new UnsupportedOperationException("Invalid selection pane: " + target.selectedView) + } + List ids = list.collect { it['nodeID'] } + def nodesFound = ScriptUtils.c().find { ids.contains(it.id) } + if (nodesFound.size() > 0) { + if (target.autoFoldMap) { + foldToTop(nodesFound[0]) + } + nodesFound.each { + unfoldBranch(it) + } + ScriptUtils.c().centerOnNode(nodesFound[0]) + ScriptUtils.c().selectMultipleNodes(nodesFound) + switchToMainWindow() + } else { + UITools.informationMessage("Error finding selection") + } + } + + catch (Exception e) { + Logger.anonymousLogger.log(Level.SEVERE, e.message, e) + } + } + + private static void switchToMainWindow() { + JFrame parentFrame = Controller.currentController.viewController.menuComponent as JFrame + for (Window window : Window.windows) { + if (parentFrame == window) { + window.toFront() + } + } + } + +// recursive unfolding of branch + private void unfoldBranch(Proxy.Node thisNode) { + Proxy.Node rootNode = thisNode.getMap().getRoot() + if (thisNode != rootNode) { + if (thisNode.folded) thisNode.setFolded(false) + unfoldBranch(thisNode.getParent()) + } + } + +// fold to first level + private void foldToTop(Proxy.Node thisNode) { + Proxy.Node rootNode = thisNode.getMap().getRoot() + def Nodes = ScriptUtils.c().findAll() + Nodes.each { + if(!it.folded) it.setFolded(true) + } + rootNode.setFolded(false) + } + +} diff --git a/src/zips/lib/freeplaneGTD/ReportModel.groovy b/lib/src/freeplaneGTD/ReportModel.groovy similarity index 100% rename from src/zips/lib/freeplaneGTD/ReportModel.groovy rename to lib/src/freeplaneGTD/ReportModel.groovy diff --git a/src/scripts/ShowTasks.groovy b/lib/src/freeplaneGTD/ReportWindow.groovy similarity index 52% rename from src/scripts/ShowTasks.groovy rename to lib/src/freeplaneGTD/ReportWindow.groovy index 1cd4f12..c8ccc6b 100644 --- a/src/scripts/ShowTasks.groovy +++ b/lib/src/freeplaneGTD/ReportWindow.groovy @@ -1,26 +1,5 @@ -// @ExecutionModes({on_single_node="main_menu_scripting/freeplaneGTD[addons.listNextActions]"}) -//========================================================= -// Freeplane GTD+ -// -// Copyright (c)2014 Gergely Papp -// -// 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 -// 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 . -// -//========================================================= -import freeplaneGTD.ClipBoardUtil -import freeplaneGTD.ReportModel -import freeplaneGTD.Tag +package freeplaneGTD + import groovy.swing.SwingBuilder import javafx.application.Platform import javafx.beans.value.ChangeListener @@ -31,13 +10,15 @@ import javafx.scene.Scene import javafx.scene.web.WebEngine import javafx.scene.web.WebView import netscape.javascript.JSObject -import org.freeplane.core.resources.ResourceBundles import org.freeplane.core.resources.ResourceController import org.freeplane.core.ui.components.UITools import org.freeplane.core.util.TextUtils import org.freeplane.features.format.FormattedDate -import org.freeplane.plugin.script.FreeplaneScriptBaseClass.ConfigProperties +import org.freeplane.features.mode.Controller +import org.freeplane.features.mode.ModeController +import org.freeplane.plugin.script.FreeplaneScriptBaseClass import org.freeplane.plugin.script.proxy.Proxy +import org.freeplane.plugin.script.proxy.ScriptUtils import javax.swing.* import java.awt.* @@ -47,38 +28,66 @@ import java.awt.event.KeyEvent import java.awt.event.WindowAdapter import java.awt.event.WindowEvent import java.lang.reflect.Field -import java.lang.reflect.Method import java.util.logging.Level import java.util.logging.Logger -import static javafx.application.Platform.runLater - -class ReportWindow { +class ReportWindow extends ModeController { static final String title = 'GTD Next Actions' static final String HTML_HEADER = '\n' static final String txtVer = '2.0.0' static final String txtURI = 'http://www.itworks.hu/index.php/freeplane-gtd+' + public static final String FREEPLANE_GTD_DEFAULT_VIEW = 'freeplaneGTD_default_view' + public static final String FREEPLANE_GTD_REMEMBER_LAST_POSITION = 'freeplaneGTD_remember_last_position' + public static final String BASE_CSS = '/**/' + + private FreeplaneScriptBaseClass.ConfigProperties config + private ReportModel report + private JFrame mainFrame + private JFXPanel projectPane + private WebView webView + private ButtonGroup contentTypeGroup + private JCheckBox cbFilterDone + + protected boolean showNotes + protected ReportModel.VIEW selectedView + + ReportWindow(Controller controller) { + super(controller) + } - static ConfigProperties config - static ReportModel report - static JFrame mainFrame - static JFXPanel projectPane - static WebView webView - static ButtonGroup contentTypeGroup - static JCheckBox cbFilterDone - - static boolean showNotes - static ReportModel.VIEW selectedView - static boolean autoFoldMap + @Override + String getModeName() { + return ReportWindow.canonicalName + } - static { + { ResourceController resourceController = ResourceController.getResourceController() try { - Field handlersField = URL.class.getDeclaredField("handlers"); - handlersField.setAccessible(true); - Hashtable handlers = handlersField.get(null) as Hashtable; + Field handlersField = URL.class.getDeclaredField("handlers") + handlersField.setAccessible(true) + Hashtable handlers = handlersField.get(null) as Hashtable //this is extremely ugly, I have to add a custom protocol handler, // because I cannot use the "bundle:" protocol in the knopflerfish due // to some weird JavaFX bug @@ -90,32 +99,21 @@ class ReportWindow { } }) } catch (Exception e) { - throw new RuntimeException(e); - } - // load i18n resources - - try { - for (lang in [ "de","es","fr", "hu", "nl", "ru"]) { - ((ResourceBundles) (resourceController.resources)). - addResources(lang, - resourceController.getResource("../translations/freeplaneGTD_" + lang + ".properties")) - } - } catch (Exception e) { - Logger.anonymousLogger.log(Level.WARNING, "Could not load i18 resource:" + e.getMessage()) + throw new RuntimeException(e) } } - static JFrame getMainFrame(ConfigProperties configModel, Proxy.Controller c) { + private JFrame getMainFrame( FreeplaneScriptBaseClass.ConfigProperties configModel) { config = configModel boolean rememberLastPosition if (!mainFrame) { String defaultView try { - defaultView = ReportModel.VIEW.valueOf(config.getProperty('freeplaneGTD_default_view')).toString() + defaultView = ReportModel.VIEW.valueOf(config.getProperty(FREEPLANE_GTD_DEFAULT_VIEW)).toString() } catch (Exception e) { defaultView = ReportModel.VIEW.PROJECT.toString() + Logger.getAnonymousLogger().log(Level.WARNING, "Cannot parse default view property:" + config.getProperty(FREEPLANE_GTD_DEFAULT_VIEW), e) } - autoFoldMap = config.getBooleanProperty('freeplaneGTD_auto_fold_map') Dimension screenSize = Toolkit.defaultToolkit.screenSize int tPosX = (int) (screenSize.width / 16 * 3) @@ -123,14 +121,14 @@ class ReportWindow { int tSizeX = (int) (screenSize.width / 4 * 3) int tSizeY = (int) (screenSize.height / 4 * 3) - rememberLastPosition = config.getBooleanProperty('freeplaneGTD_remember_last_position') + rememberLastPosition = config.getBooleanProperty(FREEPLANE_GTD_REMEMBER_LAST_POSITION) int posX = rememberLastPosition ? config.getIntProperty('freeplaneGTD_last_position_x', tPosX) : tPosX int posY = rememberLastPosition ? config.getIntProperty('freeplaneGTD_last_position_y', tPosY) : tPosY int sizeX = rememberLastPosition ? config.getIntProperty('freeplaneGTD_last_size_x', tSizeX) : tSizeX int sizeY = rememberLastPosition ? config.getIntProperty('freeplaneGTD_last_size_y', tSizeY) : tSizeY SwingBuilder.edtBuilder { - String userPath = c.userDirectory.toString() + String userPath = ScriptUtils.c().userDirectory.toString() def iconFrame = imageIcon(userPath + "/resources/images/freeplaneGTD-icon.png").image mainFrame = frame(title: title, @@ -138,83 +136,83 @@ class ReportWindow { defaultCloseOperation: JFrame.DISPOSE_ON_CLOSE, show: false) { borderLayout() - buttonPanel = panel(constraints: BorderLayout.NORTH) { + panel(constraints: BorderLayout.NORTH) { gridLayout(columns: 1, rows: 1) contentTypeGroup = buttonGroup() - projectButton = radioButton( + radioButton( buttonGroup: contentTypeGroup, actionCommand: ReportModel.VIEW.PROJECT.name(), text: "1 - " + TextUtils.getText("freeplaneGTD.tab.project.title"), toolTipText: TextUtils.getText("freeplaneGTD.tab.project.tooltip"), mnemonic: "1", selected: defaultView == "PROJECT", - actionPerformed: { refreshContent(c) } + actionPerformed: { refreshContent() } ) - whoButton = radioButton( + radioButton( buttonGroup: contentTypeGroup, actionCommand: ReportModel.VIEW.WHO.name(), text: "2 - " + TextUtils.getText("freeplaneGTD.tab.who.title"), toolTipText: TextUtils.getText("freeplaneGTD.tab.who.tooltip"), mnemonic: "2", selected: defaultView == "WHO", - actionPerformed: { refreshContent(c) } + actionPerformed: { refreshContent() } ) - contextButton = radioButton( + radioButton( buttonGroup: contentTypeGroup, actionCommand: ReportModel.VIEW.CONTEXT.name(), text: "3 - " + TextUtils.getText("freeplaneGTD.tab.context.title"), toolTipText: TextUtils.getText("freeplaneGTD.tab.context.tooltip"), mnemonic: "3", selected: defaultView == "CONTEXT", - actionPerformed: { refreshContent(c) } + actionPerformed: { refreshContent() } ) - whenButton = radioButton( + radioButton( buttonGroup: contentTypeGroup, actionCommand: ReportModel.VIEW.WHEN.name(), text: "4 - " + TextUtils.getText("freeplaneGTD.tab.when.title"), toolTipText: TextUtils.getText("freeplaneGTD.tab.when.tooltip"), mnemonic: "4", selected: defaultView == "WHEN", - actionPerformed: { refreshContent(c) } + actionPerformed: { refreshContent() } ) - aboutButton = radioButton( + radioButton( buttonGroup: contentTypeGroup, actionCommand: ReportModel.VIEW.ABOUT.name(), text: "? - " + TextUtils.getText("freeplaneGTD.tab.about.title"), toolTipText: TextUtils.getText("freeplaneGTD.tab.about.tooltip"), mnemonic: "?", - actionPerformed: { refreshContent(c) } + actionPerformed: { refreshContent() } ) } - reportPanel = panel(constraints: BorderLayout.CENTER) { + panel(constraints: BorderLayout.CENTER) { gridLayout(columns: 1, rows: 1) - } - projectPane = new JFXPanel() - Platform.setImplicitExit(false) - runLater({ - webView = new WebView() - projectPane.setScene(new Scene(webView)) - WebEngine engine = webView.getEngine() - engine.getLoadWorker().stateProperty().addListener(new ChangeListener() { - @Override - void changed(ObservableValue observable, Worker.State oldValue, Worker.State newValue) { - if (newValue == Worker.State.SUCCEEDED) { - JSObject win = engine.executeScript("window") as JSObject - win.setMember("app", new JSHandler(report, c, - ReportWindow.getMethod('refreshContent', Proxy.Controller.class))) + projectPane = new JFXPanel() + Platform.setImplicitExit(false) + + final ReportWindow currentWindow = this + Platform.runLater({ + webView = new WebView() + projectPane.setScene(new Scene(webView)) + WebEngine engine = webView.getEngine() + engine.getLoadWorker().stateProperty().addListener(new ChangeListener() { + @Override + void changed(ObservableValue observable, Worker.State oldValue, Worker.State newValue) { + if (newValue == Worker.State.SUCCEEDED) { + JSObject win = engine.executeScript("window") as JSObject + win.setMember("app", new JSHandler(report, currentWindow) as Object) + } } - } + }) + engine.loadContent("TODO: no content") }) - engine.loadContent("TODO: no content") - }) - reportPanel.add(TextUtils.getText("freeplaneGTD.tab.project.tooltip"), projectPane) + }.add(TextUtils.getText("freeplaneGTD.tab.project.tooltip"), projectPane) panel(constraints: BorderLayout.SOUTH) { boxLayout(axis: BoxLayout.X_AXIS) button(text: TextUtils.getText("freeplaneGTD.button.refresh"), actionPerformed: { - refreshContent(c) + refreshContent() }) button(text: TextUtils.getText("freeplaneGTD.button.copy"), actionPerformed: { @@ -241,13 +239,13 @@ class ReportWindow { cbFilterDone = checkBox(text: TextUtils.getText("freeplaneGTD.button.filter_done"), selected: config.getBooleanProperty('freeplaneGTD_filter_done'), actionPerformed: { - config.properties.setProperty('freeplaneGTD_filter_done', Boolean.toString(it.source.selected)) - refreshContent(c) + ScriptUtils.c().properties.put('freeplaneGTD_filter_done', Boolean.toString(it.source.selected)) + refreshContent() }) - cbShowNotes = checkBox(text: TextUtils.getText("freeplaneGTD.button.show_notes"), + checkBox(text: TextUtils.getText("freeplaneGTD.button.show_notes"), selected: showNotes, actionPerformed: { - showNotes = it.source.selected; refreshContent(c) + showNotes = it.source.selected; refreshContent() }) } } @@ -264,11 +262,11 @@ class ReportWindow { }) mainFrame.addWindowListener(new WindowAdapter() { void windowClosing(WindowEvent e) { - if (config.getBooleanProperty('freeplaneGTD_remember_last_position')) { - config.properties.setProperty('freeplaneGTD_last_position_x', Integer.toString(mainFrame.x)) - config.properties.setProperty('freeplaneGTD_last_position_y', Integer.toString(mainFrame.y)) - config.properties.setProperty('freeplaneGTD_last_position_w', Integer.toString(mainFrame.width)) - config.properties.setProperty('freeplaneGTD_last_position_h', Integer.toString(mainFrame.height)) + if (config.getBooleanProperty(FREEPLANE_GTD_REMEMBER_LAST_POSITION)) { + ScriptUtils.c().properties.put('freeplaneGTD_last_position_x', Integer.toString(mainFrame.x)) + ScriptUtils.c().properties.put('freeplaneGTD_last_position_y', Integer.toString(mainFrame.y)) + ScriptUtils.c().properties.put('freeplaneGTD_last_position_w', Integer.toString(mainFrame.width)) + ScriptUtils.c().properties.put('freeplaneGTD_last_position_h', Integer.toString(mainFrame.height)) } mainFrame.visible = false } @@ -281,11 +279,11 @@ class ReportWindow { } - static refreshContent(Proxy.Controller c) { + void refreshContent() { cbFilterDone.selected = config.getBooleanProperty('freeplaneGTD_filter_done') report.parseMap(cbFilterDone.selected) - def content + String content selectedView = ReportModel.VIEW.valueOf(contentTypeGroup.selection?.actionCommand) switch (selectedView) { case ReportModel.VIEW.WHO: content = formatList(report.delegateList(), report.mapReader.contextIcons, showNotes) @@ -296,51 +294,32 @@ class ReportWindow { break case ReportModel.VIEW.ABOUT: - Tag html = new Tag('html', - new Tag('body', [style: 'padding-left:25px']) - .addContent(new Tag('h1', 'Freeplane|').addContent('span', 'GTD', [style: 'color:#ff3300'])) - .addContent('h2', 'Version ' + txtVer) - .addContent('h4', 'by Gergely Papp') - .addContent('h5', 'based on the original code by Auxilus Systems LLC') - .addContent('h4', 'Licensed under GNU GPL Version 3') - .addContent('a', txtURI, [href: txtURI])) + Tag html = new Tag('html'). + addChild('head').addContent('style', BASE_CSS, [type: 'text/css']) + html.addChild('body', [style: 'padding-left:25px']) + .addContent(new Tag('h1', 'Freeplane|').addContent('span', 'GTD', [style: 'color:#ff3300'])) + .addContent('h2', 'Version ' + txtVer) + .addContent('h4', 'by Gergely Papp') + .addContent('h5', 'based on the original code by Auxilus Systems LLC') + .addContent('h4', 'Licensed under GNU GPL Version 3') + .addContent('a', txtURI, [href: txtURI]) content = HTML_HEADER + html.toString() break case ReportModel.VIEW.PROJECT: default: content = formatList(report.projectList(), report.mapReader.contextIcons, showNotes) } - runLater({ + Platform.runLater({ webView.engine.loadContent(content) webView.engine.reload() }) } - static String formatList(Map list, Map contextIcons, boolean showNotes) { + private static String formatList(Map list, Map contextIcons, boolean showNotes) { Tag html = new Tag('html', [xmlns: 'http://www.w3.org/1999/xhtml']) Tag head = html.addChild('head') - head.addContent('style', - '/**/', - [type: 'text/css']) + head.addContent('style', BASE_CSS, [type: 'text/css']) + head.addChild('title') Tag body = new Tag('body') Date now = new Date().clearTime() @@ -349,7 +328,12 @@ class ReportWindow { addContent('a', TextUtils.getText("freeplaneGTD.button.copy"), [href: '#', onclick: 'app.copyToClipboard(' + index + ')']). addContent('|'). addContent('a', TextUtils.getText("freeplaneGTD.button.select"), [href: '#', onclick: 'app.selectOnMap(' + index + ')']) - body.addContent('h2', it['title']) + Tag title = body.addChild('h2') + if (contextIcons.keySet().contains(it['title'])) { + title.addChild('img', [class: "contextTitleIcon", src: "fpgtd:" + contextIcons.get(it['title'] + ) + ".png", "title": it['title']]) + } + title.addContent(it['title'] as String) Tag curItem = body.addChild('ul', ['class': 'actionlist']) it['items'].each { Tag wrap = curItem.addChild('li') @@ -358,17 +342,18 @@ class ReportWindow { } wrap.addChild('A', [href: '#', onclick: 'app.toggleDone("' + it['nodeID'] + '")']).addChild('img', [class: "doneIcon", src: "fpgtd:" + (it['done'] ? "" : "un") + "checked" + ".png"]) if (it['time'] instanceof FormattedDate && ((FormattedDate) it['time']).before(now)) wrap.addProperty('class', 'overdue') + (it['context'] as String)?.tokenize(',')?.each { key -> + if (contextIcons.keySet().contains(key)) { + wrap.addChild('img', [class: "contextIcon", src: "fpgtd:" + contextIcons.get(key) + ".png", "title": key]) + } + } wrap.addChild('A', [href: '#', onclick: 'app.followLink("' + it['nodeID'] + '")']).addPreformatted(it['action'] as String) Tag contextTag = new Tag('span') - it['context']?.split(',')?.each { key -> - if (contextIcons.keySet().contains(key)) { - contextTag.addChild('img', [class: "contextIcon", src: "fpgtd:" + contextIcons.get(key) + ".png", "title": key]) - } else { - contextTag.addContent('@') - contextTag.addContent(key) - } + (it['context'] as String)?.tokenize(',')?.each { key -> + contextTag.addContent('@') + contextTag.addContent(key) } !it['who'] ?: wrap.addContent(' [' + it['who'] + ']') !it['when'] ?: wrap.addContent(' {' + it['when'] + '}') @@ -392,140 +377,21 @@ class ReportWindow { return HTML_HEADER + html.toString() } - static void refresh(Proxy.Controller c, Proxy.Node root) { - report = new ReportModel(root) - if (mainFrame?.visible) { - refreshContent(c) - } - } - -} - -class JSHandler { - private final ReportModel report - private final Proxy.Controller ctrl - private final Method refresh - - JSHandler(ReportModel report, Proxy.Controller ctrl, Method refresh) { - this.refresh = refresh - this.ctrl = ctrl - this.report = report - } - - void toggleDone(String linkNodeID) { - - try { - - def nodesFound = ctrl.find { - it.id == linkNodeID - } - - if (nodesFound[0] != null) { - def node = nodesFound[0] - if (node.icons.contains(report.mapReader.iconDone)) { - node.icons.remove(report.mapReader.iconDone) - } else { - node.icons.add(report.mapReader.iconDone) - } - refresh.invoke(null, ctrl) - } else { - UITools.informationMessage("Cannot find node to mark as done") - } - } catch (Exception e) { - System.err.println(e) - } - } - - void followLink(String linkNodeID) { - def nodesFound = ctrl.find { it.id == linkNodeID } - - if (nodesFound[0] != null) { - if (ReportWindow.autoFoldMap) { - FoldToTop(nodesFound[0]) - } - UnfoldBranch(nodesFound[0]) - ctrl.select(nodesFound[0]) - ctrl.centerOnNode(nodesFound[0]) - ctrl.centerOnNode(nodesFound[0]) - } else { - UITools.informationMessage("Next Action not found in mind map. Refresh Next Action list") - } - } - - void copyToClipboard(int pos) { - try { - Map feeder - Clipboard clip = panel.getToolkit().getSystemClipboard() - if (clip != null) { - switch (ReportWindow.selectedView) { - case ReportModel.VIEW.PROJECT: feeder = [type: 'project', groups: [report.projectList()['groups'][pos]]]; break - case ReportModel.VIEW.WHO: feeder = [type: 'who', groups: [report.delegateList()['groups'][pos]]]; break - case ReportModel.VIEW.CONTEXT: feeder = [type: 'context', groups: [report.contextList()['groups'][pos]]]; break - case ReportModel.VIEW.WHEN: feeder = [type: 'when', groups: [report.timelineList()['groups'][pos]]]; break - default: throw new UnsupportedOperationException("Invalid selection pane: " + report.selPane) - } - clip.setContents(ClipBoardUtil.createTransferable(feeder, report.mapReader, freeplaneGTD.report.ReportWindow.showNotes), null) - UITools.informationMessage(TextUtils.getText('freeplaneGTD.message.copy_ok')) - frame.toFront() - } - } catch (Exception e) { - System.err.println(e) - } + void show( FreeplaneScriptBaseClass.ConfigProperties config) { + JFrame frameinstance = getMainFrame( config) + frameinstance.visible = true } - void selectOnMap(int pos) { - try { - java.util.List list - switch (ReportWindow.selectedView) { - case ReportModel.VIEW.PROJECT: list = (java.util.List) report.projectList()['groups'][pos]['items']; break - case ReportModel.VIEW.WHO: list = (java.util.List) report.delegateList()['groups'][pos]['items']; break - case ReportModel.VIEW.CONTEXT: list = (java.util.List) report.contextList()['groups'][pos]['items']; break - case ReportModel.VIEW.WHEN: list = (java.util.List) report.timelineList()['groups'][pos]['items']; break - default: throw new UnsupportedOperationException("Invalid selection pane: " + report.selPane) - } - java.util.List ids = list.collect { it['nodeID'] } - def nodesFound = ctrl.find { ids.contains(it.id) } - if (nodesFound.size() > 0) { - if (freeplaneGTD.report.ReportWindow.autoFoldMap) { - FoldToTop(nodesFound[0]) - } - nodesFound.each { - UnfoldBranch(it) - } - ctrl.selectMultipleNodes(nodesFound) - frame.visible = false - frame.dispose() - } else { - UITools.informationMessage("Error finding selection") - } - } - - catch (Exception e) { - System.err.println(e) + void refresh(Proxy.Node root) { + report = new ReportModel(root) + if (mainFrame?.visible) { + refreshContent() } } -// recursive unfolding of branch - private void UnfoldBranch(Proxy.Node thisNode) { - Proxy.Node rootNode = thisNode.getMap().getRoot() - if (thisNode != rootNode) { - thisNode.setFolded(false) - UnfoldBranch(thisNode.getParent()) - } + boolean getAutoFoldMap() { + return config.getBooleanProperty('freeplaneGTD_auto_fold_map') } -// fold to first level - private void FoldToTop(Proxy.Node thisNode) { - Proxy.Node rootNode = thisNode.getMap().getRoot() - def Nodes = ctrl.findAll() - Nodes.each { - it.setFolded(true) - } - rootNode.setFolded(false) - } } - -JFrame frameinstance = ReportWindow.getMainFrame(config, c) -frameinstance.visible = true -ReportWindow.refresh(c, node.map.root) diff --git a/src/zips/lib/freeplaneGTD/Tag.groovy b/lib/src/freeplaneGTD/Tag.groovy similarity index 100% rename from src/zips/lib/freeplaneGTD/Tag.groovy rename to lib/src/freeplaneGTD/Tag.groovy diff --git a/lib/src/freeplaneGTD/editor/ActionEditor.groovy b/lib/src/freeplaneGTD/editor/ActionEditor.groovy new file mode 100644 index 0000000..7c2d13a --- /dev/null +++ b/lib/src/freeplaneGTD/editor/ActionEditor.groovy @@ -0,0 +1,249 @@ +package freeplaneGTD.editor + +import freeplaneGTD.DateUtil +import freeplaneGTD.GTDMapReader +import freeplaneGTD.ReportWindow +import groovy.swing.SwingBuilder +import org.freeplane.core.ui.components.UITools +import org.freeplane.core.util.TextUtils +import org.freeplane.features.mode.Controller +import org.freeplane.features.mode.ModeController +import org.freeplane.plugin.script.proxy.Proxy + +import javax.swing.AbstractAction +import javax.swing.BorderFactory +import javax.swing.BoxLayout +import javax.swing.JButton +import javax.swing.JCheckBox +import javax.swing.JComponent +import javax.swing.JDialog +import javax.swing.JFrame +import javax.swing.JTextField +import javax.swing.KeyStroke +import java.awt.Dimension +import java.awt.event.ActionEvent +import java.awt.event.KeyEvent + +class ActionEditor { + class ActionEditorModel { + String action + String delegate + String context + boolean today + String when + String priority + String waitFor + String waitUntil + boolean done + + Proxy.Node node + + boolean setNode(Proxy.Node node) { + this.node = node + GTDMapReader mapReader = GTDMapReader.instance + mapReader.findIcons(node.map.root) + mapReader.internalConvertShorthand(node) + if (!node.icons.contains(mapReader.iconNextAction)) { + UITools.errorMessage('Selected node is not a task') + return false + } + action = node.text + delegate = node.attributes['Who']?.replaceAll(',', ', ') + context = node.attributes['Where']?.replaceAll(',', ', ') + today = node.icons.contains(GTDMapReader.instance.iconToday) + when = node.attributes['When'] + priority = node.attributes['Priority'] + waitFor = node.attributes['WaitFor']?.replaceAll(',', ', ') + waitUntil = node.attributes['WaitUntil'] + done = node.icons.contains(GTDMapReader.instance.iconDone) + return true + } + + void updateNode() { + String localContext = ' @' + (context.split(',')*.trim()).join(' @') + node.text = "* $action " + + (context?.trim() ? "$localContext" : '') + + (delegate?.trim() ? "[$delegate]" : '') + + (when?.trim() ? "{$when}" : '') + + (priority?.trim() ? "#$priority" : '') + + !delegate ? node.attributes.removeAll('Who') : false + !context ? node.attributes.removeAll('Where') : false + !when ? node.attributes.removeAll('When') : false + !priority ? node.attributes.removeAll('Priority') : false + if (waitFor) { + node.attributes.set('WaitFor', waitFor.split(',')*.trim().unique({ a, b -> a.toLowerCase() <=> b.toLowerCase() }).join(',')) + } else + node.attributes.removeAll('WaitFor') + + if (waitUntil) { + def waitUntilDate = DateUtil.normalizeDate(waitUntil) + node.attributes.set('WaitUntil', waitUntilDate) + } else + node.attributes.removeAll('WaitUntil') + + GTDMapReader mapReader = GTDMapReader.instance + if (node.icons.contains(mapReader.iconToday) != today) { + if (!today) { + node.icons.remove(mapReader.iconToday) + } else { + node.icons.add(mapReader.iconToday) + } + } + if (node.icons.contains(mapReader.iconDone) != done) { + if (!done) { + node.icons.remove(mapReader.iconDone) + } else { + node.icons.add(mapReader.iconDone) + } + } + // Find icons in the entire map + mapReader.findIcons(node.map.root) + // Remove priority icons that are to be re-added by the shorthand conversion + node.icons.each { + if (it ==~ /^full\-\d$/) { + node.icons.remove(it) + } + } + // Remove all existing context icons, that are to be re-added by the shorthand conversion + node.icons.each { + if (mapReader.contextIcons.containsValue(it)) { + node.icons.remove(it) + } + } + // Only re-parse the current node + mapReader.internalConvertShorthand(node) + + + Controller currentController = Controller.currentController + ModeController reportWindow = currentController.getModeController(ReportWindow.canonicalName) + if (!reportWindow) { + reportWindow = new ReportWindow(currentController) + currentController.addModeController(reportWindow) + } + reportWindow.refresh(node.map.root) + } + } + ActionEditorModel model = new ActionEditorModel(); + + JDialog mainFrame; + JTextField actionField + JTextField delegateField + JTextField contextField + JCheckBox todayField + JTextField whenField + JTextField priorityField + JCheckBox doneField + JTextField waitForField + JTextField waitUntilField + JButton doneButton + + ActionEditor() { + SwingBuilder.edtBuilder { + mainFrame = dialog( + title: TextUtils.getText("freeplaneGTD.actioneditor.title"), + defaultCloseOperation: JFrame.DISPOSE_ON_CLOSE, + show: false, + modal: true) { + boxLayout(axis: BoxLayout.Y_AXIS) + panel(border: BorderFactory.createEmptyBorder(10, 10, 10, 10)) { + gridBagLayout() + + label(text: TextUtils.getText("freeplaneGTD.actioneditor.action"), + constraints: gbc(gridx: 0, gridy: 0, ipadx: 5, fill: HORIZONTAL)) + actionField = textField(preferredSize: new Dimension(400, 25), + constraints: gbc(gridx: 1, gridy: 0, gridwidth: REMAINDER, fill: HORIZONTAL)) + + label(text: TextUtils.getText("freeplaneGTD.actioneditor.delegate"), + constraints: gbc(gridx: 0, gridy: 1, ipadx: 5, fill: HORIZONTAL)) + delegateField = textField(preferredSize: new Dimension(300, 25), + constraints: gbc(gridx: 1, gridy: 1, gridwidth: REMAINDER, fill: HORIZONTAL)) + + label(text: TextUtils.getText("freeplaneGTD.actioneditor.context"), + constraints: gbc(gridx: 0, gridy: 2, ipadx: 5, fill: HORIZONTAL)) + contextField = textField(preferredSize: new Dimension(300, 25), + constraints: gbc(gridx: 1, gridy: 2, gridwidth: REMAINDER, fill: HORIZONTAL)) + + label(text: TextUtils.getText("freeplaneGTD.actioneditor.when"), + constraints: gbc(gridx: 0, gridy: 3, ipadx: 5, fill: HORIZONTAL)) + todayField = checkBox(text: TextUtils.getText("freeplaneGTD.actioneditor.today"), + preferredSize: new Dimension(50, 25), + constraints: gbc(gridx: 1, gridy: 3, ipadx: 5)) + whenField = textField(preferredSize: new Dimension(250, 25), + constraints: gbc(gridx: 2, gridy: 3, fill: HORIZONTAL)) + doneField = checkBox(text: TextUtils.getText("freeplaneGTD.actioneditor.done"), + constraints: gbc(gridx: 3, gridy: 3, fill: HORIZONTAL)) + + label(text: TextUtils.getText("freeplaneGTD.actioneditor.waitFor"), + constraints: gbc(gridx: 0, gridy: 4, ipadx: 5, fill: HORIZONTAL)) + waitForField = textField(preferredSize: new Dimension(250, 25), + constraints: gbc(gridx: 1, gridy: 4, gridwidth: REMAINDER, fill: HORIZONTAL)) + + label(text: TextUtils.getText("freeplaneGTD.actioneditor.waitUntil"), + constraints: gbc(gridx: 0, gridy: 5, ipadx: 5, fill: HORIZONTAL)) + waitUntilField = textField(preferredSize: new Dimension(250, 25), + constraints: gbc(gridx: 1, gridy: 5, gridwidth: REMAINDER, fill: HORIZONTAL)) + + label(text: TextUtils.getText("freeplaneGTD.actioneditor.priority"), + constraints: gbc(gridx: 0, gridy: 6, ipadx: 5, fill: HORIZONTAL)) + priorityField = textField(preferredSize: new Dimension(20, 25), + constraints: gbc(gridx: 1, gridy: 6, gridwidth: REMAINDER, fill: HORIZONTAL)) + + } + + panel() { + boxLayout(axis: BoxLayout.X_AXIS) + button(text: TextUtils.getText("freeplaneGTD.button.cancel"), + actionPerformed: { + mainFrame.setVisible(false) + mainFrame.dispose() + }) + doneButton = button(id: 'doneButton', text: TextUtils.getText("freeplaneGTD.button.done"), + actionPerformed: { + model.action = actionField.text + model.delegate = delegateField.text + model.context = contextField.text + model.today = todayField.selected + model.when = whenField.text + model.priority = priorityField.text + model.waitFor = waitForField.text + model.waitUntil = waitUntilField.text + model.done = doneField.selected + model.updateNode() + mainFrame.setVisible(false) + mainFrame.dispose() + }) + } + } + mainFrame.getRootPane().setDefaultButton(doneButton) + } + // on ESC key close frame + mainFrame.getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put( + KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), TextUtils.getText("freeplaneGTD.button.cancel")); + mainFrame.getRootPane().getActionMap().put(TextUtils.getText("freeplaneGTD.button.cancel"), + new AbstractAction() { + void actionPerformed(ActionEvent e) { + mainFrame.setVisible(false); + mainFrame.dispose(); + } + }); + } + + void editNode(Proxy.Node node) { + if (!model.setNode(node)) { + return + } + actionField.text = model.action + delegateField.text = model.delegate + contextField.text = model.context + todayField.selected = model.today + whenField.text = model.when + priorityField.text = model.priority + waitForField.text = model.waitFor + waitUntilField.text = model.waitUntil + doneField.selected = model.done + mainFrame.pack() + mainFrame.setLocationRelativeTo(UITools.frame) + mainFrame.setVisible(true) + } +} \ No newline at end of file diff --git a/lib/src/freeplaneGTD/mover/ArchiveTask.groovy b/lib/src/freeplaneGTD/mover/ArchiveTask.groovy new file mode 100644 index 0000000..5073c7e --- /dev/null +++ b/lib/src/freeplaneGTD/mover/ArchiveTask.groovy @@ -0,0 +1,21 @@ +package freeplaneGTD.mover + +import org.freeplane.core.util.TextUtils +import org.freeplane.plugin.script.proxy.Proxy + +class ArchiveTask extends DoneMover { + + public static Proxy.Node findOrCreateArchiveDir(Proxy.Node node) { + final Proxy.Node rootNode = node.map.root + final String archiveDirName = TextUtils.getText("freeplaneGTD.config.archiveDirName") + + Proxy.Node archiveNode = rootNode.children.find { + it.transformedText == archiveDirName + } + if (!archiveNode) { + archiveNode = rootNode.createChild() + archiveNode.text = archiveDirName + } + return archiveNode + } +} \ No newline at end of file diff --git a/lib/src/freeplaneGTD/mover/DoneMover.groovy b/lib/src/freeplaneGTD/mover/DoneMover.groovy new file mode 100644 index 0000000..c42d74e --- /dev/null +++ b/lib/src/freeplaneGTD/mover/DoneMover.groovy @@ -0,0 +1,59 @@ +package freeplaneGTD.mover + +import freeplaneGTD.GTDMapReader +import org.freeplane.plugin.script.proxy.Proxy + +/** + * Created by gpapp on 2016.01.24.. + */ +abstract class DoneMover { + protected final GTDMapReader mapReader = GTDMapReader.instance + + /** + * Walk up the node structure to find the project path. + * @param targetDir where to create the new directory + * @param projectDir which node we currently try to look at + * @return + */ + Proxy.Node findProjectRoot(final Proxy.Node targetDir, final Proxy.Node projectDir) { + if (projectDir == targetDir.map.root) { + return targetDir + } + Proxy.Node targetParentDir = findProjectRoot(targetDir, projectDir.parent) + if (projectDir.icons.contains(mapReader.iconProject)) { + Proxy.Node targetProjectDir = targetParentDir.children.find { it.text == projectDir.text } + if (!targetProjectDir) { + targetProjectDir = targetParentDir.appendChild(projectDir); + } + return targetProjectDir + } + return targetParentDir + } + + void execute(final Proxy.Node targetDir, final Proxy.Node node) { + // Must reread it every time in case the configuration nodes were changed + mapReader.findIcons(node.map.root) + mapReader.internalConvertShorthand(node) + + if (!node.icons.contains(mapReader.iconNextAction) || !node.icons.contains(mapReader.iconDone )) { + node.children.each { + if (it==targetDir){ + return + } + this.execute(targetDir, it) + } + return + } + + Proxy.Node targetNode = findProjectRoot(targetDir, node.parent) + Proxy.Node oldParentPtr = node.parent + node.moveTo(targetNode) + node.left=targetNode.left + + while (!oldParentPtr.children && oldParentPtr.icons.contains(mapReader.iconProject) && oldParentPtr.parent) { + Proxy.Node toDelete = oldParentPtr + oldParentPtr = oldParentPtr.parent + toDelete.delete() + } + } +} diff --git a/lib/src/freeplaneGTD/mover/ReviewTask.groovy b/lib/src/freeplaneGTD/mover/ReviewTask.groovy new file mode 100644 index 0000000..fc1ca34 --- /dev/null +++ b/lib/src/freeplaneGTD/mover/ReviewTask.groovy @@ -0,0 +1,22 @@ +package freeplaneGTD.mover + +import org.freeplane.core.util.TextUtils +import org.freeplane.plugin.script.proxy.Proxy + +class ReviewTask extends DoneMover { + + public static Proxy.Node findOrCreateReviewDir(Proxy.Node node){ + final Proxy.Node rootNode = node.map.root + final String reviewDirName = TextUtils.getText("freeplaneGTD.config.reviewDirName") + + Proxy.Node archiveNode = rootNode.children.find { + it.transformedText==reviewDirName + } + if(!archiveNode) { + archiveNode = rootNode.createChild() + archiveNode.text=reviewDirName + } + return archiveNode + } + +} \ No newline at end of file diff --git a/src/FreePlaneGTD.iml b/src/FreePlaneGTD.iml deleted file mode 100644 index 7c07d70..0000000 --- a/src/FreePlaneGTD.iml +++ /dev/null @@ -1,63 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/freeplaneGTD.addon.mm b/src/freeplaneGTD.addon.mm deleted file mode 100644 index 87b520e..0000000 --- a/src/freeplaneGTD.addon.mm +++ /dev/null @@ -1,644 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

- The homepage of this add-on should be set as the link of the root node. -

-

- The basic properties of this add-on. They can be used in script names and other attributes, e.g. "${name}.groovy". -

-
    -
  • - name: The name of the add-on, normally a technically one (no spaces, no special characters except _.-). -
  • -
  • - author: Author's name(s) and (optionally) email adresses. -
  • -
  • - version: Since it's difficult to protect numbers like 1.0 from Freeplane's number parser it's advised to prepend a 'v' to the number, e.g. 'v1.0'. -
  • -
  • - freeplane-version-from: The oldest compatible Freeplane version. The add-on will not be installed if the Freeplane version is too old. -
  • -
  • - freeplane-version-to: Normally empty: The newest compatible Freeplane version. The add-on will not be installed if the Freeplane version is too new. -
  • -
  • - updateUrl: URL of the file containing information (version, download url) on the latest version of this add-on. By default: "${homepage}/version.properties" -
  • -
- - -
- - - - - - - - - - -

- Description would be awkward to edit as an attribute. -

-

- So you have to put the add-on description as a child of the 'description' node. -

-

- To translate the description you have to define a translation for the key 'addons.${name}.description'. -

- - -
- - - - - - - -

- Freeplane|GTD creates views of GTD-style lists extracted from a mind map, providing views: -

-
    -
  • - By Project -
  • -
  • - By Context (where the next action gets done) -
  • -
  • - By Owner (who owns it, if not you) -
  • -
  • - By Due Date (when) -
  • -
-

- The completed actions can be marked and filtered, moved to Review folder or Archive folder -

-

- -

-

- Markers (icons) can be configured to correspond to contexts -

-

- -

-

- Simple action freeplaneGTD.editor is provided. -

- - -
- -
-
- - - - - - - - - -

- Change log of this add-on: append one node for each noteworthy version and put the details for each version into a child node. -

- - -
-
- - - - - - - - - -

- The add-ons's license that the user has to accept before she can install it. -

-

- -

-

- The License text has to be entered as a child of the 'license' node, either as plain text or as HTML. -

- - -
- - - -
- - - - - - - - - -

- The child node contains the add-on configuration as an extension to mindmapmodemenu.xml (in Tools->Preferences->Add-ons). -

-

- Every property in the configuration should receive a default value in default.properties node. -

- - -
- - - - - - - - - - - -

- These properties play together with the preferences: Each property defined in the preferences should have a default value in the attributes of this node. -

- - -
- - - - - -
- - - - - - - -

- The translation keys that this script uses. Define one child node per supported locale. The attributes contain the translations. Define at least -

-
    -
  • - 'addons.${name}' for the add-on's name -
  • -
  • - 'addons.${name}.description' for the description, e.g. in the add-on overview dialog (not necessary for English) -
  • -
  • - 'addons.${name}.<scriptname>' for each script since it will be the menu title. -
  • -
- - -
- - - - -
- - - - - - - - - -

- List of files and/or directories to remove on uninstall -

- - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - -

- An add-on may contain multiple scripts. The node text defines the script name (e.g. inserInlineImage.groovy). The name must have a suffix of a supported script language like .groovy or .js and may only consist of letters and digits. The script properties have to be configured via attributes: -

-

- -

-

- * menuLocation: <locationkey> -

-

-    - Defines where the menu location. -

-

-    - See mindmapmodemenu.xml for how the menu locations look like. -

-

-    - http://freeplane.bzr.sf.net/bzr/freeplane/freeplane_program/trunk/annotate/head%3A/freeplane/resources/xml/mindmapmodemenu.xml -

-

-    - This attribute is mandatory -

-

- -

-

- * menuTitleKey: <key> -

-

-    - The menu item title will be looked up under the translation key <key> - don't forget to define its translation. -

-

-    - This attribute is mandatory -

-

- -

-

- * executionMode: <mode> -

-

-    - The execution mode as described in the Freeplane wiki (http://freeplane.sourceforge.net/wiki/index.php/Scripting) -

-

-    - ON_SINGLE_NODE: Execute the script once. The node variable is set to the selected node. -

-

-    - ON_SELECTED_NODE: Execute the script n times for n selected nodes, once for each node. -

-

-    - ON_SELECTED_NODE_RECURSIVELY: Execute the script on every selected node and recursively on all of its children. -

-

-    - In doubt use ON_SINGLE_NODE. -

-

-    - This attribute is mandatory -

-

- -

-

- * keyboardShortcut: <shortcut> -

-

-    - Optional: keyboard combination / accelerator for this script, e.g. control alt I -

-

-    - Use lowercase letters for modifiers and uppercase for letters. Use no + signs. -

-

-    - The available key names are listed at http://download.oracle.com/javase/1.4.2/docs/api/java/awt/event/KeyEvent.html#VK_0 -

-

-      In the list only entries with a 'VK_' prefix count. Omit the prefix in the shortcut definition. -

-

- -

-

- * Permissions that the script(s) require, each either false or true: -

-

-    - execute_scripts_without_asking -

-

-    - execute_scripts_without_file_restriction: permission to read files -

-

-    - execute_scripts_without_write_restriction: permission to create/change/delete files -

-

-    - execute_scripts_without_exec_restriction: permission to execute other programs -

-

-    - execute_scripts_without_network_restriction: permission to access the network -

-

-   Notes: -

-

-   - The set of permissions is fixed. -

-

-   - Don't change the attribute names, don't omit one. -

-

-   - Set the values either to true or to false -

-

-   - In any case set execute_scripts_without_asking to true unless you want to annoy users. -

- - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - -

- An add-on may contain any number of nodes containing binary files (normally .jar files) to be added to the add-on's classpath. -

-

- -

-

-  - The immediate child nodes contain the name of the file, e.g. 'mysql-connector-java-5.1.25.jar'). Put the file into a 'lib' subdirectory of the add-on base directory. -

-

- -

-

-  - The child nodes of these nodes contain the actual files. -

-

- -

-

-  - Any lib file will be extracted in <installationbase>/<addonname>/lib. -

-

- -

-

-  - The files will be processed in the sequence as seen in the map. -

- - -
-
- - - - - - - - - -

- An add-on may contain any number of nodes containing zip files. -

-

- -

-

-  - The immediate child nodes contain a description of the zip. The devtools script releaseAddOn.groovy allows automatic zip creation if the name of this node matches a directory in the current directory. -

-

- -

-

-  - The child nodes of these nodes contain the actual zip files. -

-

- -

-

-  - Any zip file will be extracted in the <installationbase>. Currently, <installationbase> is always Freeplane's <userhome>, e.g. ~/.freeplane/1.3. -

-

- -

-

-  - The files will be processed in the sequence as seen in the map. -

- - -
- - - - - - - - - - - - -

- An add-on may define any number of images as child nodes of the images node. The actual image data has to be placed as base64 encoded binary data into the text of a subnode. -

-

- The images are saved to the ${installationbase}/resources/images directory. -

-

- -

-

- The following images should be present: -

-
    -
  • - ${name}-icon.png, like oldicons-theme-icon.png. This will be used in the app-on overview. -
  • -
  • - ${name}-screenshot-1.png, like oldicons-theme-screenshot-1.png. This will be used in the app-on details dialog. Further images can be included but they are not used yet. -
  • -
-

- Images can be added automatically by releaseAddOn.groovy or must be uploaded into the map via the script Tools->Scripts->Insert Binary since they have to be (base64) encoded as simple strings. -

- - -
- - - - - - - - - -
-
-
diff --git a/src/freeplane.gdsl b/src/gdsl/freeplane.gdsl similarity index 99% rename from src/freeplane.gdsl rename to src/gdsl/freeplane.gdsl index c68be5e..1983146 100644 --- a/src/freeplane.gdsl +++ b/src/gdsl/freeplane.gdsl @@ -1,5 +1,7 @@ -def groovletContext = context(filetypes: ['groovy'], scope: scriptScope()) + +def groovletContext = context(filetypes: ['groovy'], scope: scriptScope()) + contributor(groovletContext) { provider = 'Freeplane' diff --git a/src/gdsl/freeplaneGTD/swingbuilder.gdsl b/src/gdsl/freeplaneGTD/swingbuilder.gdsl new file mode 100644 index 0000000..9e60790 --- /dev/null +++ b/src/gdsl/freeplaneGTD/swingbuilder.gdsl @@ -0,0 +1,107 @@ +/* + * Copyright 2000-2010 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package freeplaneGTD + +import groovy.swing.SwingBuilder + +/** + * @author Maxim.Medvedev + */ +def groovletContext = context(ctype: SwingBuilder) + +contributor(groovletContext) { + property name: "action", type: "groovy.lang.Closure" + property name: "actions", type: "groovy.lang.Closure" + property name: "map", type: "groovy.lang.Closure" + property name: "buttonGroup", type: "groovy.lang.Closure" + property name: "bind", type: "groovy.lang.Closure" + property name: "model", type: "groovy.lang.Closure" + property name: "widget", type: "groovy.lang.Closure" + property name: "container", type: "groovy.lang.Closure" + property name: "bean", type: "groovy.lang.Closure" + property name: "dialog", type: "groovy.lang.Closure" + property name: "fileChooser", type: "groovy.lang.Closure" + property name: "frame", type: "groovy.lang.Closure" + property name: "optionPane", type: "groovy.lang.Closure" + property name: "window", type: "groovy.lang.Closure" + property name: "button", type: "groovy.lang.Closure" + property name: "checkBox", type: "groovy.lang.Closure" + property name: "checkBoxMenuItem", type: "groovy.lang.Closure" + property name: "menuItem", type: "groovy.lang.Closure" + property name: "radioButton", type: "groovy.lang.Closure" + property name: "radioButtonMenuItem", type: "groovy.lang.Closure" + property name: "toggleButton", type: "groovy.lang.Closure" + property name: "editorPane", type: "groovy.lang.Closure" + property name: "label", type: "groovy.lang.Closure" + property name: "passwordField", type: "groovy.lang.Closure" + property name: "textArea", type: "groovy.lang.Closure" + property name: "textField", type: "groovy.lang.Closure" + property name: "textPane", type: "groovy.lang.Closure" + property name: "colorChooser", type: "groovy.lang.Closure" + property name: "comboBox", type: "groovy.lang.Closure" + property name: "desktopPane", type: "groovy.lang.Closure" + property name: "formattedTextField", type: "groovy.lang.Closure" + property name: "internalFrame", type: "groovy.lang.Closure" + property name: "layeredPane", type: "groovy.lang.Closure" + property name: "list", type: "groovy.lang.Closure" + property name: "menu", type: "groovy.lang.Closure" + property name: "menuBar", type: "groovy.lang.Closure" + property name: "panel", type: "groovy.lang.Closure" + property name: "popupMenum", type: "groovy.lang.Closure" + property name: "progressBar", type: "groovy.lang.Closure" + property name: "scrollBar", type: "groovy.lang.Closure" + property name: "scrollPane", type: "groovy.lang.Closure" + property name: "separator", type: "groovy.lang.Closure" + property name: "slider", type: "groovy.lang.Closure" + property name: "spinner", type: "groovy.lang.Closure" + property name: "splitPane", type: "groovy.lang.Closure" + property name: "tabbedPane", type: "groovy.lang.Closure" + property name: "table", type: "groovy.lang.Closure" + property name: "tableColumn", type: "groovy.lang.Closure" + property name: "toolbar", type: "groovy.lang.Closure" + property name: "tree", type: "groovy.lang.Closure" + property name: "viewport", type: "groovy.lang.Closure" + property name: "boundedRangeModel", type: "groovy.lang.Closure" + property name: "spinnerDateModel", type: "groovy.lang.Closure" + property name: "spinnerListModel", type: "groovy.lang.Closure" + property name: "spinnerNumberModel", type: "groovy.lang.Closure" + property name: "tableModel", type: "groovy.lang.Closure" + property name: "propertyColumn", type: "groovy.lang.Closure" + property name: "closureColumn", type: "groovy.lang.Closure" + property name: "borderLayout", type: "groovy.lang.Closure" + property name: "cardLayout", type: "groovy.lang.Closure" + property name: "flowLayout", type: "groovy.lang.Closure" + property name: "gridBagLayout", type: "groovy.lang.Closure" + property name: "gridLayout", type: "groovy.lang.Closure" + property name: "overlayLayout", type: "groovy.lang.Closure" + property name: "springLayout", type: "groovy.lang.Closure" + property name: "gridBagConstraints", type: "groovy.lang.Closure" + property name: "gbc", type: "groovy.lang.Closure" + property name: "boxLayout", type: "groovy.lang.Closure" + property name: "box", type: "groovy.lang.Closure" + property name: "hbox", type: "groovy.lang.Closure" + property name: "hglue", type: "groovy.lang.Closure" + property name: "hstrut", type: "groovy.lang.Closure" + property name: "vbox", type: "groovy.lang.Closure" + property name: "vglue", type: "groovy.lang.Closure" + property name: "vstrut", type: "groovy.lang.Closure" + property name: "glue", type: "groovy.lang.Closure" + property name: "rigidArea", type: "groovy.lang.Closure" + property name: "tableLayout", type: "groovy.lang.Closure" + property name: "tr", type: "groovy.lang.Closure" + property name: "td", type: "groovy.lang.Closure" + property name: "imageIcon", type: "groovy.lang.Closure" +} \ No newline at end of file diff --git a/src/resources/freeplaneGTD.addon.mm b/src/resources/freeplaneGTD.addon.mm new file mode 100644 index 0000000..9f478ca --- /dev/null +++ b/src/resources/freeplaneGTD.addon.mm @@ -0,0 +1,1005 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+ The homepage of this add-on should be set as the link of the root node. +

+

+ The basic properties of this add-on. They can be used in script names and other attributes, e.g. "${name}.groovy". +

+
    +
  • + name: The name of the add-on, normally a technically one (no spaces, no special characters except _.-). +
  • +
  • + author: Author's name(s) and (optionally) email adresses. +
  • +
  • + version: Since it's difficult to protect numbers like 1.0 from Freeplane's number parser it's advised to prepend a 'v' to the number, e.g. 'v1.0'. +
  • +
  • + freeplane-version-from: The oldest compatible Freeplane version. The add-on will not be installed if the Freeplane version is too old. +
  • +
  • + freeplane-version-to: Normally empty: The newest compatible Freeplane version. The add-on will not be installed if the Freeplane version is too new. +
  • +
  • + updateUrl: URL of the file containing information (version, download url) on the latest version of this add-on. By default: "${homepage}/version.properties" +
  • +
+ + +
+ + + + + + + + + + +

+ Description would be awkward to edit as an attribute. +

+

+ So you have to put the add-on description as a child of the 'description' node. +

+

+ To translate the description you have to define a translation for the key 'addons.${name}.description'. +

+ + +
+ + + + + + + +

+ Freeplane|GTD creates views of GTD-style lists extracted from a mind map, providing views: +

+
    +
  • + By Project +
  • +
  • + By Context (where the next action gets done) +
  • +
  • + By Owner (who owns it, if not you) +
  • +
  • + By Due Date (when) +
  • +
+

+ The completed actions can be marked and filtered, moved to Review folder or Archive folder +

+

+ +

+

+ Markers (icons) can be configured to correspond to contexts +

+

+ +

+

+ Simple action freeplaneGTD.editor is provided. +

+ + +
+ +
+
+ + + + + + + + + +

+ Change log of this add-on: append one node for each noteworthy version and put the details for each version into a child node. +

+ + +
+
+ + + + + + + + + +

+ The add-ons's license that the user has to accept before she can install it. +

+

+ +

+

+ The License text has to be entered as a child of the 'license' node, either as plain text or as HTML. +

+ + +
+ + + +
+ + + + + + + + + +

+ The child node contains the add-on configuration as an extension to mindmapmodemenu.xml (in Tools->Preferences->Add-ons). +

+

+ Every property in the configuration should receive a default value in default.properties node. +

+ + +
+ + + + + + + + + + + +

+ These properties play together with the preferences: Each property defined in the preferences should have a default value in the attributes of this node. +

+ + +
+ + + + + +
+ + + + + + + +

+ The translation keys that this script uses. Define one child node per supported locale. The attributes contain the translations. Define at least +

+
    +
  • + 'addons.${name}' for the add-on's name +
  • +
  • + 'addons.${name}.description' for the description, e.g. in the add-on overview dialog (not necessary for English) +
  • +
  • + 'addons.${name}.<scriptname>' for each script since it will be the menu title. +
  • +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + +

+ List of files and/or directories to remove on uninstall +

+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + +

+ An add-on may contain multiple scripts. The node text defines the script name (e.g. inserInlineImage.groovy). The name must have a suffix of a supported script language like .groovy or .js and may only consist of letters and digits. The script properties have to be configured via attributes: +

+

+ +

+

+ * menuLocation: <locationkey> +

+

+    - Defines where the menu location. +

+

+    - See mindmapmodemenu.xml for how the menu locations look like. +

+

+    - http://freeplane.bzr.sf.net/bzr/freeplane/freeplane_program/trunk/annotate/head%3A/freeplane/resources/xml/mindmapmodemenu.xml +

+

+    - This attribute is mandatory +

+

+ +

+

+ * menuTitleKey: <key> +

+

+    - The menu item title will be looked up under the translation key <key> - don't forget to define its translation. +

+

+    - This attribute is mandatory +

+

+ +

+

+ * executionMode: <mode> +

+

+    - The execution mode as described in the Freeplane wiki (http://freeplane.sourceforge.net/wiki/index.php/Scripting) +

+

+    - ON_SINGLE_NODE: Execute the script once. The node variable is set to the selected node. +

+

+    - ON_SELECTED_NODE: Execute the script n times for n selected nodes, once for each node. +

+

+    - ON_SELECTED_NODE_RECURSIVELY: Execute the script on every selected node and recursively on all of its children. +

+

+    - In doubt use ON_SINGLE_NODE. +

+

+    - This attribute is mandatory +

+

+ +

+

+ * keyboardShortcut: <shortcut> +

+

+    - Optional: keyboard combination / accelerator for this script, e.g. control alt I +

+

+    - Use lowercase letters for modifiers and uppercase for letters. Use no + signs. +

+

+    - The available key names are listed at http://download.oracle.com/javase/1.4.2/docs/api/java/awt/event/KeyEvent.html#VK_0 +

+

+      In the list only entries with a 'VK_' prefix count. Omit the prefix in the shortcut definition. +

+

+ +

+

+ * Permissions that the script(s) require, each either false or true: +

+

+    - execute_scripts_without_asking +

+

+    - execute_scripts_without_file_restriction: permission to read files +

+

+    - execute_scripts_without_write_restriction: permission to create/change/delete files +

+

+    - execute_scripts_without_exec_restriction: permission to execute other programs +

+

+    - execute_scripts_without_network_restriction: permission to access the network +

+

+   Notes: +

+

+   - The set of permissions is fixed. +

+

+   - Don't change the attribute names, don't omit one. +

+

+   - Set the values either to true or to false +

+

+   - In any case set execute_scripts_without_asking to true unless you want to annoy users. +

+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + +

+ An add-on may contain any number of nodes containing binary files (normally .jar files) to be added to the add-on's classpath. +

+

+ +

+

+  - The immediate child nodes contain the name of the file, e.g. 'mysql-connector-java-5.1.25.jar'). Put the file into a 'lib' subdirectory of the add-on base directory. +

+

+ +

+

+  - The child nodes of these nodes contain the actual files. +

+

+ +

+

+  - Any lib file will be extracted in <installationbase>/<addonname>/lib. +

+

+ +

+

+  - The files will be processed in the sequence as seen in the map. +

+ + +
+
+ + + + + + + + + +

+ An add-on may contain any number of nodes containing zip files. +

+

+ +

+

+  - The immediate child nodes contain a description of the zip. The devtools script releaseAddOn.groovy allows automatic zip creation if the name of this node matches a directory in the current directory. +

+

+ +

+

+  - The child nodes of these nodes contain the actual zip files. +

+

+ +

+

+  - Any zip file will be extracted in the <installationbase>. Currently, <installationbase> is always Freeplane's <userhome>, e.g. ~/.freeplane/1.3. +

+

+ +

+

+  - The files will be processed in the sequence as seen in the map. +

+ + +
+ + + + + + + + + + + +

+ An add-on may define any number of images as child nodes of the images node. The actual image data has to be placed as base64 encoded binary data into the text of a subnode. +

+

+ The images are saved to the ${installationbase}/resources/images directory. +

+

+ +

+

+ The following images should be present: +

+
    +
  • + ${name}-icon.png, like oldicons-theme-icon.png. This will be used in the app-on overview. +
  • +
  • + ${name}-screenshot-1.png, like oldicons-theme-screenshot-1.png. This will be used in the app-on details dialog. Further images can be included but they are not used yet. +
  • +
+

+ Images can be added automatically by releaseAddOn.groovy or must be uploaded into the map via the script Tools->Scripts->Insert Binary since they have to be (base64) encoded as simple strings. +

+ + +
+ + + + + + + + + +
+
+
diff --git a/src/images/fpgtdLogo.png b/src/resources/images/fpgtdLogo.png similarity index 100% rename from src/images/fpgtdLogo.png rename to src/resources/images/fpgtdLogo.png diff --git a/src/images/fpgtdLogo.xcf b/src/resources/images/fpgtdLogo.xcf similarity index 100% rename from src/images/fpgtdLogo.xcf rename to src/resources/images/fpgtdLogo.xcf diff --git a/src/images/freeplaneGTD-icon.png b/src/resources/images/freeplaneGTD-icon.png similarity index 100% rename from src/images/freeplaneGTD-icon.png rename to src/resources/images/freeplaneGTD-icon.png diff --git a/src/images/freeplaneGTD-icon.xcf b/src/resources/images/freeplaneGTD-icon.xcf similarity index 100% rename from src/images/freeplaneGTD-icon.xcf rename to src/resources/images/freeplaneGTD-icon.xcf diff --git a/src/images/freeplaneGTD.png b/src/resources/images/freeplaneGTD.png similarity index 100% rename from src/images/freeplaneGTD.png rename to src/resources/images/freeplaneGTD.png diff --git a/src/resources/scripts/ArchiveTask.groovy b/src/resources/scripts/ArchiveTask.groovy new file mode 100644 index 0000000..ecfd75a --- /dev/null +++ b/src/resources/scripts/ArchiveTask.groovy @@ -0,0 +1,25 @@ +// @ExecutionModes({on_single_node="main_menu_scripting/freeplaneGTD[addons.archiveTask]"}) +/* +========================================================= + Freeplane GTD+ + + Copyright (c)2016 Gergely Papp + + 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 + 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 . + +========================================================= +*/ +freeplaneGTD.mover.ArchiveTask archiveTask = new freeplaneGTD.mover.ArchiveTask() +archiveTask.execute(freeplaneGTD.mover.ArchiveTask.findOrCreateArchiveDir(node), node) + diff --git a/src/resources/scripts/EditTask.groovy b/src/resources/scripts/EditTask.groovy new file mode 100644 index 0000000..7b93a3d --- /dev/null +++ b/src/resources/scripts/EditTask.groovy @@ -0,0 +1,27 @@ +// @ExecutionModes({on_single_node="main_menu_scripting/freeplaneGTD[addons.editAction]"}) +//========================================================= +// Freeplane GTD+ +// +// Copyright (c)2014 Gergely Papp +// +// 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 +// 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 . +// +//========================================================= +import freeplaneGTD.ReportWindow +import freeplaneGTD.editor.ActionEditor +import org.freeplane.features.mode.Controller +import org.freeplane.features.mode.ModeController + +ActionEditor editor = new ActionEditor() +editor.editNode(node) diff --git a/src/resources/scripts/ParseShorthand.groovy b/src/resources/scripts/ParseShorthand.groovy new file mode 100644 index 0000000..90e7fe8 --- /dev/null +++ b/src/resources/scripts/ParseShorthand.groovy @@ -0,0 +1,33 @@ +// @ExecutionModes({on_single_node="main_menu_scripting/freeplaneGTD[addons.parseShorthand]"}) +//========================================================= +// Freeplane GTD+ +// +// Copyright (c)2016 Gergely Papp +// +// 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 +// 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 . +// +//========================================================= + + +import freeplaneGTD.ReportWindow +import org.freeplane.features.mode.Controller +import org.freeplane.features.mode.ModeController + +Controller currentController = Controller.currentController +ModeController reportWindow = currentController.getModeController(ReportWindow.canonicalName) +if (!reportWindow) { + reportWindow = new ReportWindow(currentController) + currentController.addModeController(reportWindow) +} +reportWindow.refresh(node.map.root) diff --git a/src/resources/scripts/ReviewTask.groovy b/src/resources/scripts/ReviewTask.groovy new file mode 100644 index 0000000..932986e --- /dev/null +++ b/src/resources/scripts/ReviewTask.groovy @@ -0,0 +1,25 @@ +// @ExecutionModes({on_single_node="main_menu_scripting/freeplaneGTD[addons.archiveTask]"}) +/* +========================================================= + Freeplane GTD+ + + Copyright (c)2016 Gergely Papp + + 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 + 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 . + +========================================================= +*/ +freeplaneGTD.mover.ReviewTask reviewTask = new freeplaneGTD.mover.ReviewTask() +reviewTask.execute(freeplaneGTD.mover.ReviewTask.findOrCreateReviewDir(node), node) + diff --git a/src/resources/scripts/ShowTasks.groovy b/src/resources/scripts/ShowTasks.groovy new file mode 100644 index 0000000..e56e456 --- /dev/null +++ b/src/resources/scripts/ShowTasks.groovy @@ -0,0 +1,33 @@ +// @ExecutionModes({on_single_node="main_menu_scripting/freeplaneGTD[addons.listNextActions]"}) +//========================================================= +// Freeplane GTD+ +// +// Copyright (c)2014 Gergely Papp +// +// 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 +// 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 . +// +//========================================================= +import freeplaneGTD.ReportWindow +import org.freeplane.features.mode.Controller +import org.freeplane.features.mode.ModeController + +Controller currentController = Controller.currentController +ModeController reportWindow = currentController.getModeController(ReportWindow.canonicalName) +if (!reportWindow) { + reportWindow = new ReportWindow(currentController) + currentController.addModeController(reportWindow) +} + +reportWindow.show(config) +reportWindow.refresh(node.map.root) \ No newline at end of file diff --git a/src/zips/icons/fpgtdIcon.png b/src/resources/zips/icons/fpgtdIcon.png similarity index 100% rename from src/zips/icons/fpgtdIcon.png rename to src/resources/zips/icons/fpgtdIcon.png diff --git a/src/zips/templates/GTD_template.mm b/src/resources/zips/templates/GTD_template.mm similarity index 100% rename from src/zips/templates/GTD_template.mm rename to src/resources/zips/templates/GTD_template.mm diff --git a/src/zips/translations/freeplaneGTD_de.properties b/src/resources/zips/translations/freeplaneGTD_de.properties similarity index 100% rename from src/zips/translations/freeplaneGTD_de.properties rename to src/resources/zips/translations/freeplaneGTD_de.properties diff --git a/src/zips/translations/freeplaneGTD_en.properties b/src/resources/zips/translations/freeplaneGTD_en.properties similarity index 100% rename from src/zips/translations/freeplaneGTD_en.properties rename to src/resources/zips/translations/freeplaneGTD_en.properties diff --git a/src/zips/translations/freeplaneGTD_es.properties b/src/resources/zips/translations/freeplaneGTD_es.properties similarity index 100% rename from src/zips/translations/freeplaneGTD_es.properties rename to src/resources/zips/translations/freeplaneGTD_es.properties diff --git a/src/zips/translations/freeplaneGTD_fr.properties b/src/resources/zips/translations/freeplaneGTD_fr.properties similarity index 100% rename from src/zips/translations/freeplaneGTD_fr.properties rename to src/resources/zips/translations/freeplaneGTD_fr.properties diff --git a/src/zips/translations/freeplaneGTD_hu.properties b/src/resources/zips/translations/freeplaneGTD_hu.properties similarity index 100% rename from src/zips/translations/freeplaneGTD_hu.properties rename to src/resources/zips/translations/freeplaneGTD_hu.properties diff --git a/src/zips/translations/freeplaneGTD_nl.properties b/src/resources/zips/translations/freeplaneGTD_nl.properties similarity index 100% rename from src/zips/translations/freeplaneGTD_nl.properties rename to src/resources/zips/translations/freeplaneGTD_nl.properties diff --git a/src/zips/translations/freeplaneGTD_ru.properties b/src/resources/zips/translations/freeplaneGTD_ru.properties similarity index 100% rename from src/zips/translations/freeplaneGTD_ru.properties rename to src/resources/zips/translations/freeplaneGTD_ru.properties diff --git a/src/scripts/ArchiveTask.groovy b/src/scripts/ArchiveTask.groovy index 228555a..ecfd75a 100644 --- a/src/scripts/ArchiveTask.groovy +++ b/src/scripts/ArchiveTask.groovy @@ -20,7 +20,6 @@ ========================================================= */ - - -archiveTask.execute(ArchiveTask.findOrCreateArchiveDir(node), node) +freeplaneGTD.mover.ArchiveTask archiveTask = new freeplaneGTD.mover.ArchiveTask() +archiveTask.execute(freeplaneGTD.mover.ArchiveTask.findOrCreateArchiveDir(node), node) diff --git a/src/scripts/EditTask.groovy b/src/scripts/EditTask.groovy index d66e987..7b93a3d 100644 --- a/src/scripts/EditTask.groovy +++ b/src/scripts/EditTask.groovy @@ -18,7 +18,10 @@ // along with this program. If not, see . // //========================================================= +import freeplaneGTD.ReportWindow import freeplaneGTD.editor.ActionEditor +import org.freeplane.features.mode.Controller +import org.freeplane.features.mode.ModeController ActionEditor editor = new ActionEditor() editor.editNode(node) diff --git a/src/scripts/Harness.groovy b/src/scripts/Harness.groovy deleted file mode 100644 index 329c08c..0000000 --- a/src/scripts/Harness.groovy +++ /dev/null @@ -1,69 +0,0 @@ -import freeeplaneHarness.MyController -import org.freeplane.core.resources.ResourceBundles -import org.freeplane.features.mode.Controller -import org.freeplane.main.application.ApplicationResourceController -import org.freeplane.plugin.script.FreeplaneScriptBaseClass -import org.freeplane.plugin.script.proxy.Proxy -import org.knopflerfish.framework.FrameworkContext -import org.knopflerfish.framework.ServiceURLStreamHandlerFactory - -import javax.swing.* -import java.awt.* -import java.awt.event.ActionEvent - -/** - * Created by gpapp on 2017.05.28.. - */ -class Harness implements Runnable { - private static final String PROPERTY_FILE = "harness/keys.properties" - - @Override - void run() { - JFrame frame = new JFrame("Test harness") - JToolBar bar = new JToolBar() - frame.add(bar) - - def resourceController = new ApplicationResourceController() - Controller.currentController = new MyController(resourceController, frame) - ((ResourceBundles) resourceController.resources). - addResources("hu", new URL("file:src/zips/translations/freeplaneGTD_en.properties")) - - ServiceURLStreamHandlerFactory streamHandlerFactory = new ServiceURLStreamHandlerFactory() - URL.setURLStreamHandlerFactory(streamHandlerFactory) - streamHandlerFactory.addFramework(new FrameworkContext([ - "org.osgi.framework.security": "", - "org.osgi.framework.storage" : "/usr/share/freeplane/fwdir"])) - def config = new FreeplaneScriptBaseClass.ConfigProperties() - - Proxy.Map map = Controller.currentController.newMap() - addNode(map, "ID__1", "*test task 1") - addNode(map, "ID__2", "*test task 2 {2017-06-19}") - addNode(map, "ID__3", "*test task 3 #3 {2017-06-19} @Context1 @Context2") - - def frameinstance = null - JButton refreshButton = new JButton("Refresh") - frame.layout = new BorderLayout() - refreshButton.action = new AbstractAction() { - @Override - void actionPerformed(ActionEvent e) { - def controller = Controller.currentController - frameinstance = ReportWindow.getMainFrame(config, controller) - frameinstance.visible = true - ReportWindow.refresh(controller, map.root) - } - } - - frame.add(refreshButton) - frame.defaultCloseOperation = JFrame.EXIT_ON_CLOSE - frame.visible = true - frame.setLocation(10, 10) - frame.setSize(100, 100) - - } - - private static void addNode(Proxy.Map map, String id, String text) { - Proxy.Node child = map.root.createChild() - child.text = text - map.root.appendChild(child) - } -} diff --git a/src/scripts/ParseShorthand.groovy b/src/scripts/ParseShorthand.groovy index 269bfdb..90e7fe8 100644 --- a/src/scripts/ParseShorthand.groovy +++ b/src/scripts/ParseShorthand.groovy @@ -19,10 +19,15 @@ // //========================================================= -//========================================================= -// references -//========================================================= -//========================================================= -// script -//========================================================= -ReportWindow.refresh(node.map.root) \ No newline at end of file + +import freeplaneGTD.ReportWindow +import org.freeplane.features.mode.Controller +import org.freeplane.features.mode.ModeController + +Controller currentController = Controller.currentController +ModeController reportWindow = currentController.getModeController(ReportWindow.canonicalName) +if (!reportWindow) { + reportWindow = new ReportWindow(currentController) + currentController.addModeController(reportWindow) +} +reportWindow.refresh(node.map.root) diff --git a/src/scripts/ReviewTask.groovy b/src/scripts/ReviewTask.groovy index d856ee3..932986e 100644 --- a/src/scripts/ReviewTask.groovy +++ b/src/scripts/ReviewTask.groovy @@ -20,7 +20,6 @@ ========================================================= */ - - -reviewTask.execute(ReviewTask.findOrCreateReviewDir(node), node) +freeplaneGTD.mover.ReviewTask reviewTask = new freeplaneGTD.mover.ReviewTask() +reviewTask.execute(freeplaneGTD.mover.ReviewTask.findOrCreateReviewDir(node), node) diff --git a/test/lib/freeplaneGTD/GTDMapReaderTest.groovy b/test/lib/freeplaneGTD/GTDMapReaderTest.groovy index 9f3bc6c..59fa38f 100644 --- a/test/lib/freeplaneGTD/GTDMapReaderTest.groovy +++ b/test/lib/freeplaneGTD/GTDMapReaderTest.groovy @@ -1,26 +1,12 @@ package freeplaneGTD -import com.thoughtworks.xstream.core.util.ArrayIterator -import freeeplaneHarness.MyNode -import org.freeplane.core.ui.LengthUnits -import org.freeplane.core.util.Quantity -import org.freeplane.features.filter.condition.ICondition -import org.freeplane.plugin.script.proxy.Convertible +import org.freeplane.features.map.MapModel +import org.freeplane.features.map.NodeModel +import org.freeplane.plugin.script.ScriptContext import org.freeplane.plugin.script.proxy.Proxy -import org.freeplane.plugin.script.proxy.Proxy.Attributes -import org.freeplane.plugin.script.proxy.Proxy.Cloud -import org.freeplane.plugin.script.proxy.Proxy.Connector -import org.freeplane.plugin.script.proxy.Proxy.ExternalObject -import org.freeplane.plugin.script.proxy.Proxy.Link -import org.freeplane.plugin.script.proxy.Proxy.Map -import org.freeplane.plugin.script.proxy.Proxy.Node -import org.freeplane.plugin.script.proxy.Proxy.NodeRO -import org.freeplane.plugin.script.proxy.Proxy.NodeStyle -import org.freeplane.plugin.script.proxy.Proxy.Reminder +import org.freeplane.plugin.script.proxy.ProxyFactory import org.junit.Test -import java.util.Map.Entry - class GTDMapReaderTest { @Test @@ -75,21 +61,21 @@ class GTDMapReaderTest { @Test public void testConvertShortHand() { - MyNode rootNode = new MyNode() + Proxy.Node rootNode = ProxyFactory.createNode(new NodeModel(new MapModel()),new ScriptContext()) rootNode.icons.add('aa') rootNode.text = 'aa' - MyNode child1 = rootNode.createChild(); + Proxy.Node child1 = rootNode.createChild(); child1.text = 'bb' - MyNode child2 = rootNode.createChild(); + Proxy.Node child2 = rootNode.createChild(); child2.text = 'cc' - MyNode child3 = rootNode.createChild(); + Proxy.Node child3 = rootNode.createChild(); child3.text = 'dd' assert rootNode.text == 'aa' assert child1.text == 'bb' assert child2.text == 'cc' assert child3.text == 'dd' - MyNode configNode = rootNode.createChild(); + Proxy.Node configNode = rootNode.createChild(); configNode.text = 'Config' List config = [ [text: 'Icon: Project', icon: 'project'], @@ -100,7 +86,7 @@ class GTDMapReaderTest { [text: 'Icon: @Email', icon: 'email'], ]; config.each { - MyNode n = configNode.createChild() + Proxy.Node n = configNode.createChild() n.text = it['text'] n.icons.add(it['icon']) } @@ -132,7 +118,7 @@ class GTDMapReaderTest { ] testvalues.each { - MyNode n = child1.createChild() + Proxy.Node n = child1.createChild() n.text = it['orig'] mapreader.convertShorthand(rootNode) assert n.text == it['action'] diff --git a/test/Archive test.mm b/test/resources/Archive test.mm similarity index 100% rename from test/Archive test.mm rename to test/resources/Archive test.mm diff --git a/test/freeplaneGTD-test-gtd.mm b/test/resources/freeplaneGTD-test-gtd.mm similarity index 100% rename from test/freeplaneGTD-test-gtd.mm rename to test/resources/freeplaneGTD-test-gtd.mm