The Freeplane Task Time Tracker

2012-01-06
2012-10-07
  • Hi all, and Happy New Year !

    I have made a Freeplane Task Time Tracker (together with my own Pomodoro
    "engine") a few months ago and was intending to not release it because it's
    part of a bigger GTD project and also because it does need some refinements
    and is not bug free, although it works perfectly for my needs.

    Due to lack of time and programming competence, this project has been idle for
    a while.

    But seeing other people interested, I submit it as is for now as I'm sure many
    of you will definitely be interested in the project itself, the interactions
    between the script and the freeplane map and in the Groovy programming
    techniques used, as this is not very much documented (kudos to Völker for the
    help).

    I posted a video of the tracker in action :
    http://http://www.youtube.com/watch?v=PSCY0zG9eto

    I will posts the scripts tomorrow.

    The Freeplane Task Time Tracker is basically a form, listing all preselected
    tasks from a todo list node.

    It's based on and inspired by many Todo lists and GTD systems.

    Each task listed in the form has a start and stop button, to monitor the time
    you work on this task.

    You decide which task you're working on, record the working time and may use a
    Pomodoro "engine" to block a selected period of time.
    You can't work on 2 tasks at once (ideally, lol), so if you have to interrupt
    and switch to another task, just press the "Stop" button for the first task
    and the "Start" button for the new task.

    Displayed information includes :

    • the starting time for the current task
    • the duration for all the temporarily stopped and / or finished tasks
    • the total woking time for the day
    • color highlight codes for pending (blue), current (yellow), interrupted (red) and finished tasks (green)

    All this information is recorded in attributes, which are created
    automatically for each selected tasks (currently this is a separate script,
    but it could easily be included).

    At the bottom of the form, you have a flexible Pomodoro "engine". Pomodoro is
    an idea, but you are not restricted to using 25 minutes periods of work time;
    that's why I let the user select different blocks of time (from 5 to 6O
    minutes). An interesting enhancement would be to play a sound when the time
    block is expired (like Yu did; will definitely try to implement it).

    To use it, you have to have a node on your map (anywhere you like) with
    today's date, together with a child node named ToDoNow, where all tasks node
    should be listed; I actually do this via another script, but you can place
    them there manually.
    Upon launching the script, all tasks are read from the ToDoNow list (node
    children) and listed in the Task Timer form

    Caveat : there is currently no error management if there is no node with
    today's date.

    So at the moment, it's only a sophisticated todo list with timers, the
    Pomodoro "engine".

    Current implementation is partly in french (as it was a personal project), but
    this should be no problem; the major thing is the dates are formatted in
    french, but it should be easy to configure it for any formatting.

    There is a button to update the current state of tasks in your freeplane map :
    so you can track how much time you worked on a task and eventually, how long
    you spent on a project. This part is not completed and the button is
    deactivated, but you get the idea how it can make sense in a complete GTD
    project tool using Freeplane.

    Also, there are some unexploited features, like the tabs which are mostly not
    used; it's pretty clear that I would like to use them to store other
    contextual items in the GTD spirit.

    I have other ideas, only partially tested/implemented to use Freeplane as a
    full GTD system; Freeplane is ideal to organize, manage and visualize project
    informations; coupled with the Freeplane Task Time Tracker, I feel it can be a
    great productivity tool.

    Regards,
    Michel

     
  • Here we go with the scripts :

    1. Create 1 or several days with a GTD like structure
      This is a variation of a script already published, I believe :

      // @ExecutionModes({ON_SINGLE_NODE})
      //ui.informationMessage(ui.frame, temp)

      //import java.awt.Color;
      import org.freeplane.plugin.script.proxy.Proxy.Node

      // ========================= Config BEGIN =========================
      // create as child of selected node or child of root node ? "true" = selected node / "false" = root node
      def fromSelectedNode = "false"
      // Name of containing node
      def newNodeName = "Agenda"
      // Number of days to create
      def daysToCreate = 1
      // Maximum number of nodes to remain unfolded
      def unfoldedNodes = 1
      // choose your prefered date format : (ex : "yyyy-MM-dd hh:mm")
      def dateFormat = "dd/MM/yy"
      // define edge color
      def String edgeColor = "#006699"
      // define edge width
      def edgeWidth = 2
      // assign edge color like parent node ? "true" / "false"
      parentEdgeColor = "false"
      // assign edge width like parent node ? "true" / "false"
      parentEdgeWidth = "true"
      // define recurrent items within each day
      def daysCategories = ["Todo" , "Delegated To", "Phone Calls", "Appointments", "Meetings", "Events", "New Inbox"]
      // ========================= Config END =========================

      // color information : [url]http://chir.ag/projects/name-that-color/#6183ED[/url]
      // Colors codes used:
      clr = [ "BahamaBlue":"#006699"
      , "WildSand":"#f5f5f5"
      , "Gray":"#999999"
      , "VerdunGreen":"#336600"
      , "Orange":"#ff9933"
      , "Black":"#000000"
      , "Yellow":"#ffff00"
      , "White":"#ffffff"
      , "Red":"#ff0000"

      , "Pink":"#ff9999"]

      // Functions
      def void formatNode(Node node, String nodeTextColor, String nodeBgColor, nodeFontSize, String edgeColor, edgeWidth) {
      node.style.font.bold = 0
      node.style.setTextColorCode(nodeTextColor)
      node.style.setBackgroundColorCode(nodeBgColor)
      node.style.font.size = nodeFontSize
      node.style.edge.setColorCode(edgeColor)
      node.style.edge.setWidth(edgeWidth)
      }

      def today = new Date()
      def f = new java.text.SimpleDateFormat(dateFormat)
      todaySimple = f.format(today)

      def nextday = today

      if ( parentEdgeColor == "true")
      edgeColor = c.selected.style.edge.getColorCode()

      if ( parentEdgeWidth == "true")
      edgeWidth = c.selected.style.edge.getWidth()

      def newNode
      if ( fromSelectedNode == "true"){
      newNode = c.selected.createChild()
      } else {
      newNode = node.map.root.createChild()
      }

      newNode.text = newNodeName
      //newNode.style.name = "Step"

      formatNode(newNode, clr.White, clr.Red, 14, edgeColor , edgeWidth)

      i = 0
      while ( i++ < daysToCreate ) {
      def child = newNode.createChild()
      child.text = f.format(nextday)
      child.attributes =
      "totalJournée" : ""

      daysCategories.each() {
      def cat = child.createChild()
      cat.text = it
      }

      if (i > unfoldedNodes)
          child.setFolded(true)
      nextday++
      

      }
      def todayCats
      c.find{
      it.text == todaySimple
      }.each {
      formatNode(it, clr.Black, clr.Yellow, 13, edgeColor , edgeWidth)
      c.select (it)
      it.setFolded(false)
      todayCats = it.getChildren()
      }

      todayCats.each{
      if (it.text == "Todo")
      it.text = "ToDoNow"
      }

    Assign it to a Function key.

    1. The Freplane Task Time Tracker

    2. Creates the necessary attributes in each task in the ToDoNow node

    3. opens the Tracker form

      // @ExecutionModes({ON_SINGLE_NODE})
      // ui.informationMessage(ui.frame, temp )

      import groovy.time.*
      import java.util.Timer;
      import javax.swing.BorderFactory
      import java.awt.Color
      import groovy.swing.SwingBuilder
      import java.awt.FlowLayout as FL
      import javax.swing.BoxLayout as BXL
      import javax.swing.JFrame
      import javax.swing.JScrollPane
      import javax.swing.JTabbedPane
      import javax.swing.JOptionPane
      import java.awt.Font
      import javax.swing.ImageIcon

      def colorWhite = new Color(255, 255, 255) // white
      def colorBlack = new Color(0, 0, 0) // black
      def colorRed = new Color(255, 0, 0) // red
      def colorBlue = new Color(225, 235, 254) // light blue
      def colorYellow = new Color(240, 250, 208) // light yellow
      def colorRose = new Color(245, 230, 229) // light rose
      def colorGreen = new Color(206, 253, 218) // light green
      def colorOrange = new Color(253, 233, 206) // light orange
      def colorPurple = new Color(246, 192, 251) // light purple
      def colorGray = new Color(255,255,255) // gray

      def tabCenter = 28

      def f = new java.text.SimpleDateFormat( "dd/MM/yy HH:mm:ss" )
      def fDay = new java.text.SimpleDateFormat( "dd/MM/yy" )
      def fTime = new java.text.SimpleDateFormat( "HH:mm:ss" )
      def fDurée = new java.text.SimpleDateFormat( "HH:mm" )
      def fMoisAnnée = new java.text.SimpleDateFormat( "MMMM yyyy", new Locale('FR'))

      dateJour = fDay.format(new Date())

      c.find{ it.text == dateJour }.each { today = it}
      today.setFolded(false)

      todayChillen = today.getChildren()
      todayChillen.find{it.text == "ToDoNow"}.each {
      ToDoNow = it
      c.select(it)
      it.setFolded(false)
      }

      listeNextActions = ToDoNow.getChildren()

      listeNextActions.each {

      it['début'] = ""
      it['arrêt'] = ""
      it['fin'] =  ""
      it['total'] = ""
      it['totalJour'] = ""
      

      }

      def totalJournée = today['totalJournée']
      def tempsTotalJournée = elapsedToMillis(totalJournée)

      c.find{ it.text == "ToDos"}.each{inbox = it}

      def elapsedTime(diff, précision, format){

      def time
      
      long secondInMillis = 1000;
      long minuteInMillis = secondInMillis * 60;
      long hourInMillis = minuteInMillis * 60;
      long dayInMillis = hourInMillis * 24;
      long yearInMillis = dayInMillis * 365;
      
      long elapsedYears = diff / yearInMillis;
      diff = diff % yearInMillis;
      long elapsedDays = diff / dayInMillis;
      diff = diff % dayInMillis;
      long elapsedHours = diff / hourInMillis;
      diff = diff % hourInMillis;
      long elapsedMinutes = diff / minuteInMillis;
      diff = diff % minuteInMillis;
      long elapsedSeconds = diff / secondInMillis;
      diff = diff % secondInMillis;
      
      elapsedSecondsString = String.format("%02d", elapsedSeconds)
      elapsedMinutesString = String.format("%02d", elapsedMinutes)
      elapsedHoursString = String.format("%02d", elapsedHours)
      
      if (précision == "sec" && format == "long")
          time = elapsedHoursString + " heures, " + elapsedMinutesString + " minutes, " + elapsedSecondsString +  " secondes"
      if (précision == "sec" && format == "court")
          time = elapsedHoursString + " h " + elapsedMinutesString + " m " + elapsedSecondsString +  " s"
      
      if (précision== "min" && format == "long")
          time = elapsedHours + " heures, " + elapsedMinutes + " minutes" 
      if (précision== "min" && format == "court")
          time = elapsedHours + " h " + elapsedMinutes + " m"
      
      if (précision== "pomodoro" && format == "court")
          time = elapsedMinutesString + " m " + elapsedSecondsString +  " s"
      return time
      

      }
      def elapsedToMillis(elapsed){

      def elapsedInMillis 
      if (elapsed == ""){
          elapsedInMillis = 0
      }else{
          def elapsedHours = Integer.parseInt(elapsed[0..1])
          def elapsedMinutes = Integer.parseInt(elapsed[5..6])
          def elapsedSeconds = Integer.parseInt(elapsed[10..11])
          elapsedInMillis = (elapsedSeconds * 1000) + (elapsedMinutes * 60 * 1000) + (elapsedHours * 60 * 60 * 1000)
      }
      return elapsedInMillis
      

      }

      Font font = new Font("Serif", Font.BOLD, 13)
      Font pom = new Font("Serif", Font.BOLD, 28)

      def s = new SwingBuilder()
      s.setVariable('myDialog-properties', [:])
      def vars = s.variables
      def dial = s.dialog(title: 'Freeplane Task Time Tracker', id: 'myDialog', size: [930, 542], locationRelativeTo: ui.frame, owner: ui.frame,
      defaultCloseOperation: JFrame.DISPOSE_ON_CLOSE, visible:true, show: true ) {

      tabbedPane(id: 'tabs',  opaque : false, tabLayoutPolicy:JTabbedPane.SCROLL_TAB_LAYOUT) {
          tabs.setFont(font)
      
          def actionsTabName = "Actions : " + listeNextActions.size().toString()
          panel(name:  actionsTabName.center(tabCenter) , background: colorWhite, foreground: colorBlue) {                              
              boxLayout(axis: BXL.Y_AXIS)
      
              def totalTâchesVal = "Total : " + listeNextActions.size().toString() + " actions"
      
              def totalJour
              def total
      
              def initNextActionID 
              def initPanelID
      
              def lastAction = "Stop"
      
              j = -1
              while ( j++ < listeNextActions.size() -1 ) {
                  initNextActionID = listeNextActions[j].getId()
                  initPanelID = "panel$initNextActionID"
      
                  c.find{
                      it.getId() == initNextActionID
                  }.each {
                      totalJour = elapsedToMillis(it['totalJour'])                        
                      tempsTotalJournée += totalJour
                  }
              }
      
              tempsTotalJournéeVal = (elapsedTime(tempsTotalJournée, "sec", "long")).toString()
      
              panel(id : 'résumé', alignmentX: 0f, preferredSize: [900, 40]){
              boxLayout(axis: BXL.X_AXIS)
                  panel(alignmentX: 0f,  background: colorWhite) {
                      flowLayout(alignment: FL.LEFT) 
                      label ( dateJour, preferredSize: [104, 24]).setFont(font) 
                      totalTâches = label (totalTâchesVal, preferredSize: [150, 24]).setFont(font) 
                  }
      
                  panel(alignmentX: 0f, background: colorWhite) {
                      flowLayout(alignment: FL.RIGHT) 
                      label (id :'totalTemps',text: "Temps total : $tempsTotalJournéeVal", preferredSize: [270, 24]).setFont(font) 
                  }
              }       
              scrollPane( verticalScrollBarPolicy:JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED ,background: colorWhite) {
                  vbox {      
                      i = -1
                      while ( i++ < listeNextActions.size() -1 ) {
      
                          def nextAction = listeNextActions[i].text
                          def nextActionID = listeNextActions[i].getId()
                          def thisNode = listeNextActions[i]
                          def panelID = "panel$nextActionID"
                          def doneID = "donedone$nextActionID"
      
                          def débutID 
                          def finID    
                          def diffID
      
                          c.find{
                              it.getId() == nextActionID
                          }.each {
                              if( it['totalJour'] != "")
                                  diffID = it['totalJour'].toString()
      
                              if( it['fin'] != "" ){                      
                                  s."$doneID"  = "checked"
                              }else{
                                  s."$doneID" = "unchecked" 
                              }
                          }
      
                          thisActionOriginId = thisNode['ID']
                          c.find{
                              it.getId() == thisActionOriginId.toString()
                          }.each {                        
                              def note = it.note
                              def details = it.details.getPlain()
                          }
      
                          def débutID_Val = "début" + "$i" + "Val"
                          def débutID_ValTime = "début" + "$i" + "Time"
      
                          def finID_Val = "fin" + "$i" + "Val"
                          def finID_ValTime = "fin" + "$i" + "Time"
      
                          panel( id: '$panelID' , alignmentX: 0f ) {
                              boxLayout(axis: BXL.X_AXIS)
      
                              def pane = panel(id: panelID , alignmentX: 0f , preferredSize: [100, 35], background: colorBlue , border: BorderFactory.createMatteBorder(0, 0, 1, 0, colorGray)) {
                                  flowLayout(alignment: FL.LEFT) 
                                  checkBox(id:'check$i', preferredSize: [20, 24], opaque: false, selected: (s."$doneID"  == "checked" ? true : false), actionPerformed: {
      
                                      c.find{
                                          it.getId() == nextActionID
                                      }.each {
                                          c.select(it)
                                          if (it['fin'] == ""){
                                              s."$doneID" = "checked"
                                              it['fin'] = it['arrêt'] 
                                              s."$panelID".background = colorGreen
                                              }else{  
                                              it['fin'] = ""
                                              s."$doneID"  = "unchecked"
                                              s."$panelID".background = colorBlue
                                          }
                                      }
                                  })
                                  if (s."$doneID"  == "checked"){
                                      s."$panelID".background = colorGreen
                                  }else{
                                      s."$panelID".background = colorBlue
                                  }
                                  label(id :'todo$i', text: nextAction, preferredSize: [530, 24])
                                  button( id:'startButton$i', text:'Start', preferredSize: [60, 24], actionPerformed: {
      
                                      if (lastAction == "Stop" && s."$doneID"  == "unchecked"){
      
                                          lastAction = "Start"
                                          activeID = nextActionID
      
                                          s."$panelID".background = colorYellow
      
                                          débutID_Val = new Date()
                                          débutID.text =  fTime.format(débutID_Val)
                                          débutID_ValTime = débutID_Val.getTime()
                                          c.find{
                                              it.getId() == nextActionID
      
                                          }.each {
                                          c.select(it)
                                              if( it['début'] == "")
                                                  it['début'] = f.format(débutID_Val)                                             
                                              finID.text = "" 
                                          }
                                      }
                                  })
      
                                  button( id:'stopButton$i', text:'Stop', visible: true,  preferredSize: [60, 24], actionPerformed: {
      
                                      if (lastAction == "Start" && activeID == nextActionID && s."$doneID"  == "unchecked"){
      
                                          lastAction = "Stop"
                                          currentActionID = nextActionID
                                          j = -1
                                          while ( j++ < listeNextActions.size() -1 ) {
                                              initNextActionID = listeNextActions[j].getId()
                                              initPanelID = "panel$initNextActionID"
                                              if (s."$doneID"  == "checked"){
                                                  s."$panelID".background = colorGreen
                                              }else{
                                                  s."$panelID".background = colorBlue
                                              }                                       
                                          }
                                          s."$panelID".background = colorRose
      
                                          finID_Val = new Date()
                                          finID.text =  fTime.format(finID_Val)
                                          finID_ValTime = finID_Val.getTime()
      
                                          c.find{
                                              it.getId() == nextActionID
                                          }.each {
                                              c.select(it)
                                              différence = finID_ValTime - débutID_ValTime                
                                              it['arrêt'] = f.format(finID_Val)
      
                                              totalJour = elapsedToMillis(it['totalJour'])
                                              totalJour += différence
                                              it['totalJour'] = (elapsedTime(totalJour, "sec", "court")).toString()
      
                                              diffID.text = elapsedTime(totalJour, "sec", "court")
      
                                              total = elapsedToMillis(it['total'])
                                              total += différence                                     
                                              it['total'] = (elapsedTime(total, "sec", "court")).toString()
      
                                              tempsTotalJournée += différence                     
                                              tempsTotalJournéeVal = (elapsedTime(tempsTotalJournée, "sec", "long")).toString()
                                              totalTemps.text = "Temps total : $tempsTotalJournéeVal"
                                          }
                                      }
                                  })
      
                                  débutID = label(débutID , preferredSize: [50, 24])
                                  finID = label(finID , preferredSize: [50, 24])
                                  diffID = label(diffID , preferredSize: [70, 24])
                              }
                          }
                      }
                  }
              }
          }
          panel(name: 'Delegated To'.center(tabCenter)) {
              borderLayout()
              splitPane() {
                  panel(constraints: 'left') {
                      label(text: 'Left')
                  }
                  panel(constraints: 'right') {
                      label(text: 'Right')
                  }
              }
          }       
          panel(name: 'Phone Calls'.center(tabCenter)) {
              textField(text: 'Some text', columns: 15)
              scrollPane() {
                  textArea(text: 'Some text', columns: 15, rows: 4)
              }
          }
          panel(name: 'Appointments'.center(tabCenter)) {
              borderLayout()
              splitPane() {
                  panel(constraints: 'left') {
                      label(text: 'Left')
                  }
                  panel(constraints: 'right') {
                      label(text: 'Right')
                  }
              }
          }
          panel(name: 'Meetings'.center(tabCenter)) {
              borderLayout()
              splitPane() {
                  panel(constraints: 'left') {
                      label(text: 'Left')
                  }
                  panel(constraints: 'right') {
                      label(text: 'Right')
                  }
              }
          }
          panel(name: 'Events'.center(tabCenter)) {
              borderLayout()
              splitPane() {
                  panel(constraints: 'left') {
                      label(text: 'Left')
                  }
                  panel(constraints: 'right') {
                      label(text: 'Right')
                  }
              }
          }
      
          panel(name: 'Inbox'.center(tabCenter)) {
              boxLayout(axis: BXL.Y_AXIS) 
              panel( ){
                  label('nouvelle entrée').setFont(font) 
                  button('ajout TodoNow', actionPerformed:{
                      // deactivated
                      })
                  input = textField(columns:87,
                      background: colorYellow,
                      actionPerformed: { 
                          output.text +=  input.text + "\n"
                          input.text =""
                      })
                  }
              panel(alignmentY: 0f,){                         
                  scrollPane(verticalScrollBarPolicy:JScrollPane.VERTICAL_SCROLLBAR_ALWAYS) {
                      output = textArea(id="liste", text: '', columns: 110, rows: 18)
                  }
              }
          }   
      }
      def togglePomPanel
      def task
      
      boxLayout(axis: BXL.Y_AXIS)     
      panel(id:'Pomodoro', background: colorWhite){
      
          togglePomPanel = "OFF"
          //button('Pomodoro',icon:new ImageIcon("pomodoro30x30-tr.png"),  actionPerformed:{
      
          button('Pomodoro', actionPerformed:{
              if (togglePomPanel == "OFF"){
                  Pomodoro.background = colorRed
                  pomodoroLabel.setForeground(colorWhite)
                  togglePomPanel = "ON"
      
              def pomodoroVal = pomodor.selectedItem
              def pomodoro = pomodoroVal*60000
      
              use (TimerMethods) {
                  def timer = new Timer()
                  def fPomo = new java.text.SimpleDateFormat( "mm:ss" )
      
                  pomodoroLabel.text = '   ' +(elapsedTime(pomodoro, "pomodoro", "court")).toString()
                  pomodoro -= 1000
      
                  task = timer.runEvery(1000, 1000) {
      
                      while ( pomodoro > -1000 ){
                          pomodoroLabel.text = '   ' + (elapsedTime(pomodoro, "pomodoro", "court")).toString()
                          break                           
                      }
                      pomodoro -= 1000
      
                      if (pomodoro < 0 && togglePomPanel == "ON"){
                              Pomodoro.background = colorWhite
                              togglePomPanel = "OFF"
                              pomodoroLabel.setForeground(colorBlack)
                              task.cancel()
                      }
                  }
              }
              }
          })
          comboBox(
              id: 'pomodor', 
              items: [60,45,25,15,10,5,2,1], 
              selectedIndex: 2, 
              preferredSize: [50, 24]
          )       
          label(id : 'pomodoroLabel' , '   00 m 00 s').setFont(pom)
          label(icon:new ImageIcon("Progress_quarter_03.svg"))    
      }
      
      panel(id:'secondPanel', background: colorWhite){                       
          button('Fin de session : mettre à jour et quitter', actionPerformed:{
              ui.informationMessage(ui.frame, "this should update each tasks duration attributes and manage archiving of past tasks"  )
              // dispose()
          })              
      }
      

      }

      // Mr Haki File: newtimer.groovy
      // [url]http://mrhaki.blogspot.com/2009/11/groovy-goodness-run-code-at-specified.html[/url]

      class GroovyTimerTask extends TimerTask {
      Closure closure
      void run() {
      closure()
      }
      }

      class TimerMethods {
      static TimerTask runEvery(Timer timer, long delay, long period, Closure codeToRun) {
      TimerTask task = new GroovyTimerTask(closure: codeToRun)
      timer.schedule task, delay, period
      task
      }
      }

     
  • This standard BBcode should embed the video here :

    PSCY0zG9eto

     
  • Quinbus
    Quinbus
    2012-01-07

    Michel,

    FYI: The second script abends after the basic timer screen is rendered and
    total tasks calculated, reporting an error to the effect that "ScrollPane can
    only have one child component..."

    Q!

     
  • Hi Q!,

    the script as published is working and I checked the code : but there are no
    instances where there would be such case where a scrollPane is having more
    than 1 child : I know because I tried to do it earlier, and I got that same
    error.

    I will take time to republish downloadable scripts in the wiki, to avoid any
    error while copying.

    Thanks for reporting.

    Michel.

     
  • Miguel Boyer
    Miguel Boyer
    2012-01-09

    Bon soir Michel.

    Great job. Pitty it doesn't work for me either. Hoping you post the code again
    soon. Will you tel us when you have time to do it?
    Thanks again. :)

     
  • uploaded to the wiki.
    I need to post some explanations there too and would like to simplify /
    integrate the whole ; not sure yet how

    I will test tomorrow with the very latest FP version.

    Michel

     
  • Miguel Boyer
    Miguel Boyer
    2012-01-10

    Salut Michel.
    It is not working for me. I had Groovy 1.6, so i'm installing the 1.8, see if
    it helps.
    Thanks.

     
  • Miguel Boyer
    Miguel Boyer
    2012-01-10

    Well...
    I get "Error executing the script: null"
    Using 1.2.11 beta version of Freeplane.
    Hopefully waiting for your instructions, later today.

     
  • It is not working for me. I had Groovy 1.6, so i'm installing the 1.8, see
    if it helps.

    Freeplane comes with its own Groovy library (1.8.x) and it is using that
    exclusively. It doesn't matter, which Groovy version you have installed on
    your machine.

    When posting bug reports you should include the last Exception error message
    from the log (it's a multi-line message with many source locations starting
    with "at").

    Volker

     
  • Miguel Boyer
    Miguel Boyer
    2012-01-10

    Dear Volker...

    Oh, thanks for the warning about the way to report!
    I am a bit ashamed. To begin with, i am starting to think I may not have
    installed correctily something about my java. Like Freeplane does not access
    libraries correctly?

    Again, a bit confused-ashamed. If i'm wasting you guys time, just let me know
    and i will stop posting. (I am very interested in freeplane, have been using
    freemind for years, but i have infant programing skills, maybe to far away for
    you guys time).

    Well, here goes my log (very long, though):

    STDOUT: message: No such property: today for class: Script1
    STDOUT: Line number: -1Jan 10, 2012 12:09:14 PM
    org.freeplane.core.util.LogUtils warn
    WARNING: error executing script C:\Users\Miguel\AppData\Roaming\Freeplane\1.2.
    x\scripts\FreeplaneTaskTimeTracker.groovy - giving up
    org.freeplane.plugin.script.ExecuteScriptException: No such property: today
    for class: Script1 at line -1
    at org.freeplane.plugin.script.ScriptingEngine.executeScript(ScriptingEngine.j
    ava:169)
    at org.freeplane.plugin.script.ScriptingEngine.executeScript(ScriptingEngine.j
    ava:209)
    at org.freeplane.plugin.script.ExecuteScriptAction.actionPerformed(ExecuteScri
    ptAction.java:99)
    at org.freeplane.core.ui.AccelerateableAction.actionPerformed(AccelerateableAc
    tion.java:176)
    at javax.swing.AbstractButton.fireActionPerformed(Unknown Source)
    at javax.swing.AbstractButton$Handler.actionPerformed(Unknown Source)
    at javax.swing.DefaultButtonModel.fireActionPerformed(Unknown Source)
    at javax.swing.DefaultButtonModel.setPressed(Unknown Source)
    at javax.swing.AbstractButton.doClick(Unknown Source)
    at javax.swing.plaf.basic.BasicMenuItemUI.doClick(Unknown Source)
    at javax.swing.plaf.basic.BasicMenuItemUI$Handler.mouseReleased(Unknown
    Source)
    at java.awt.Component.processMouseEvent(Unknown Source)
    at javax.swing.JComponent.processMouseEvent(Unknown Source)
    at java.awt.Component.processEvent(Unknown Source)
    at java.awt.Container.processEvent(Unknown Source)
    at java.awt.Component.dispatchEventImpl(Unknown Source)
    at java.awt.Container.dispatchEventImpl(Unknown Source)
    at java.awt.Component.dispatchEvent(Unknown Source)
    at java.awt.LightweightDispatcher.retargetMouseEvent(Unknown Source)
    at java.awt.LightweightDispatcher.processMouseEvent(Unknown Source)
    at java.awt.LightweightDispatcher.dispatchEvent(Unknown Source)
    at java.awt.Container.dispatchEventImpl(Unknown Source)
    at java.awt.Window.dispatchEventImpl(Unknown Source)
    at java.awt.Component.dispatchEvent(Unknown Source)
    at java.awt.EventQueue.dispatchEventImpl(Unknown Source)
    at java.awt.EventQueue.access$000(Unknown Source)
    at java.awt.EventQueue$1.run(Unknown Source)
    at java.awt.EventQueue$1.run(Unknown Source)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.security.AccessControlContext$1.doIntersectionPrivilege(Unknown
    Source)
    at java.security.AccessControlContext$1.doIntersectionPrivilege(Unknown
    Source)
    at java.awt.EventQueue$2.run(Unknown Source)
    at java.awt.EventQueue$2.run(Unknown Source)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.security.AccessControlContext$1.doIntersectionPrivilege(Unknown
    Source)
    at java.awt.EventQueue.dispatchEvent(Unknown Source)
    at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
    at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
    at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
    at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
    at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
    at java.awt.EventDispatchThread.run(Unknown Source)
    Caused by: groovy.lang.MissingPropertyException: No such property: today for
    class: Script1
    at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.unwrap(ScriptBytecodeAdap
    ter.java:50)
    at org.codehaus.groovy.runtime.callsite.PogoGetPropertySite.getProperty(PogoGe
    tPropertySite.java:49)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callGroovyObjectGetPr
    operty(AbstractCallSite.java:231)
    at Script1.run(Script1.groovy:39)
    at org.freeplane.plugin.script.ScriptingEngine$2.evaluate(ScriptingEngine.java
    :134)
    at groovy.lang.GroovyShell.evaluate(GroovyShell.java:618)
    at groovy.lang.GroovyShell.evaluate(GroovyShell.java:589)
    at org.freeplane.plugin.script.ScriptingEngine.executeScript(ScriptingEngine.j
    ava:145)
    ... 41 more
    Jan 10, 2012 12:09:14 PM org.freeplane.core.util.LogUtils warn
    WARNING: Error executing the script:
    No such property: today for class: Script1 at line -1

     
  • Hi Pilominco,

    I'm currently testing and am a bit puzzled because I can't reproduce a
    consistent error :

    • script works with latest FP version
    • when downloading from wiki I sometimes get the error
    • there is no difference btw the downloaded script and the original uploaded script : I checked line for line, character and spaces too

    So I'm trying to reproduce consistent conditions to identify the error.

    However, the log file indicates (probably) that the script doesn't find the
    variable "today"
    Either :
    - you didn't run the first script ( http://freeplane.sourceforge.net/wiki/index.php/Scripting:_Example_scripts#Create_a_Today_GTD_simple_framework)

    or :
    - there is a problem with the date format.

    I will make some additions / explanations or allow for configurations for
    dates.

    As I explained, I uploaded a script

     
  • Miguel Boyer
    Miguel Boyer
    2012-01-10

    Actually, the log i sent is NOT the first error i was getting.
    Originally, i got errors saying things about weird characters in the script.
    So i Changed accented letters in the script:
    é -> xex
    â -> xax
    and then i stopped getting errors related to characters and got the one i sent
    before.
    But beeing more thorough, i am reverting to your script exactly as posted, and
    i will send you the log with the original error, no to introduce more
    confusion on the whole thing. Will do that in a moment, when i get to the
    other machine.
    In any case: Seems like problems with accented characters, and then with
    dates!!! Sounds like lange configurations, but i didn't expect those things to
    arise in this context. Who knows!

    Thank you again and again. : )
    (Hopeffully we will all finally get time efficient with your help!)

     
  • Miguel Boyer
    Miguel Boyer
    2012-01-10

    Hey Michel:

    Sorry to have you confused. Here goes my error log after running first the
    prepraring script, and then the tracker, both of them as downloaded from the
    wiki (not changing anything this time). See if it can be reproduced now..
    (Thanx ). (Why your "é" is giving problems, i have no clue):

    STDOUT: message: startup failed:
    Script1.groovy: 33: unexpected char: 0xA9 @ line 33, column 10.
    def fDurée = new java.text.SimpleDateFormat( "HH:mm" )
    ^

    1 error

    STDOUT: Line number: 33Jan 10, 2012 4:37:17 PM
    org.freeplane.core.util.LogUtils warn
    WARNING: error executing script C:\Users\Miguel\AppData\Roaming\Freeplane\1.2.
    x\scripts\FreeplaneTaskTimeTracker.groovy - giving up
    org.freeplane.plugin.script.ExecuteScriptException: startup failed:
    Script1.groovy: 33: unexpected char: 0xA9 @ line 33, column 10.
    def fDurée = new java.text.SimpleDateFormat( "HH:mm" )
    ^

    1 error
    at line 33
    at org.freeplane.plugin.script.ScriptingEngine.executeScript(ScriptingEngine.j
    ava:169)
    at org.freeplane.plugin.script.ScriptingEngine.executeScript(ScriptingEngine.j
    ava:209)
    at org.freeplane.plugin.script.ExecuteScriptAction.actionPerformed(ExecuteScri
    ptAction.java:99)
    at org.freeplane.core.ui.AccelerateableAction.actionPerformed(AccelerateableAc
    tion.java:176)
    at javax.swing.AbstractButton.fireActionPerformed(Unknown Source)
    at javax.swing.AbstractButton$Handler.actionPerformed(Unknown Source)
    at javax.swing.DefaultButtonModel.fireActionPerformed(Unknown Source)
    at javax.swing.DefaultButtonModel.setPressed(Unknown Source)
    at javax.swing.AbstractButton.doClick(Unknown Source)
    at javax.swing.plaf.basic.BasicMenuItemUI.doClick(Unknown Source)
    at javax.swing.plaf.basic.BasicPopupMenuUI$Actions.doReturn(Unknown Source)
    at javax.swing.plaf.basic.BasicPopupMenuUI$Actions.actionPerformed(Unknown
    Source)
    at javax.swing.SwingUtilities.notifyAction(Unknown Source)
    at javax.swing.JComponent.processKeyBinding(Unknown Source)
    at javax.swing.KeyboardManager.fireBinding(Unknown Source)
    at javax.swing.KeyboardManager.fireKeyboardAction(Unknown Source)
    at javax.swing.JComponent.processKeyBindingsForAllComponents(Unknown Source)
    at javax.swing.JComponent.processKeyBindings(Unknown Source)
    at javax.swing.JComponent.processKeyEvent(Unknown Source)
    at java.awt.Component.processEvent(Unknown Source)
    at java.awt.Container.processEvent(Unknown Source)
    at java.awt.Component.dispatchEventImpl(Unknown Source)
    at java.awt.Container.dispatchEventImpl(Unknown Source)
    at java.awt.Component.dispatchEvent(Unknown Source)
    at java.awt.KeyboardFocusManager.redispatchEvent(Unknown Source)
    at java.awt.DefaultKeyboardFocusManager.dispatchKeyEvent(Unknown Source)
    at java.awt.DefaultKeyboardFocusManager.preDispatchKeyEvent(Unknown Source)
    at java.awt.DefaultKeyboardFocusManager.typeAheadAssertions(Unknown Source)
    at java.awt.DefaultKeyboardFocusManager.dispatchEvent(Unknown Source)
    at java.awt.Component.dispatchEventImpl(Unknown Source)
    at java.awt.Container.dispatchEventImpl(Unknown Source)
    at java.awt.Window.dispatchEventImpl(Unknown Source)
    at java.awt.Component.dispatchEvent(Unknown Source)
    at java.awt.EventQueue.dispatchEventImpl(Unknown Source)
    at java.awt.EventQueue.access$000(Unknown Source)
    at java.awt.EventQueue$1.run(Unknown Source)
    at java.awt.EventQueue$1.run(Unknown Source)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.security.AccessControlContext$1.doIntersectionPrivilege(Unknown
    Source)
    at java.security.AccessControlContext$1.doIntersectionPrivilege(Unknown
    Source)
    at java.awt.EventQueue$2.run(Unknown Source)
    at java.awt.EventQueue$2.run(Unknown Source)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.security.AccessControlContext$1.doIntersectionPrivilege(Unknown
    Source)
    at java.awt.EventQueue.dispatchEvent(Unknown Source)
    at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
    at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
    at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
    at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
    at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
    at java.awt.EventDispatchThread.run(Unknown Source)
    Caused by: org.codehaus.groovy.control.MultipleCompilationErrorsException:
    startup failed:
    Script1.groovy: 33: unexpected char: 0xA9 @ line 33, column 10.
    def fDurée = new java.text.SimpleDateFormat( "HH:mm" )
    ^

    1 error

    at org.codehaus.groovy.control.ErrorCollector.failIfErrors(ErrorCollector.java
    :302)
    at org.codehaus.groovy.control.ErrorCollector.addFatalError(ErrorCollector.jav
    a:149)
    at
    org.codehaus.groovy.control.ErrorCollector.addError(ErrorCollector.java:119)
    at
    org.codehaus.groovy.control.ErrorCollector.addError(ErrorCollector.java:131)
    at org.codehaus.groovy.control.SourceUnit.addError(SourceUnit.java:359)
    at org.codehaus.groovy.antlr.AntlrParserPlugin.transformCSTIntoAST(AntlrParser
    Plugin.java:136)
    at org.codehaus.groovy.antlr.AntlrParserPlugin.parseCST(AntlrParserPlugin.java
    :107)
    at org.codehaus.groovy.control.SourceUnit.parse(SourceUnit.java:236)
    at
    org.codehaus.groovy.control.CompilationUnit$1.call(CompilationUnit.java:163)
    at org.codehaus.groovy.control.CompilationUnit.applyToSourceUnits(CompilationU
    nit.java:839)
    at org.codehaus.groovy.control.CompilationUnit.doPhaseOperation(CompilationUni
    t.java:544)
    at org.codehaus.groovy.control.CompilationUnit.processPhaseOperations(Compilat
    ionUnit.java:520)
    at
    org.codehaus.groovy.control.CompilationUnit.compile(CompilationUnit.java:497)
    at groovy.lang.GroovyClassLoader.doParseClass(GroovyClassLoader.java:306)
    at groovy.lang.GroovyClassLoader.parseClass(GroovyClassLoader.java:287)
    at groovy.lang.GroovyShell.parseClass(GroovyShell.java:731)
    at groovy.lang.GroovyShell.parse(GroovyShell.java:743)
    at org.freeplane.plugin.script.ScriptingEngine$2.evaluate(ScriptingEngine.java
    :130)
    at groovy.lang.GroovyShell.evaluate(GroovyShell.java:618)
    at groovy.lang.GroovyShell.evaluate(GroovyShell.java:589)
    at org.freeplane.plugin.script.ScriptingEngine.executeScript(ScriptingEngine.j
    ava:145)
    ... 50 more
    Jan 10, 2012 4:37:17 PM org.freeplane.core.util.LogUtils warn
    WARNING: Error executing the script:
    startup failed:
    Script1.groovy: 33: unexpected char: 0xA9 @ line 33, column
    10.
    def fDurée = new java.text.SimpleDateFormat( "HH:mm" )

    ^

    1 error
    at line 33

     
  • I just removed all accented characters, in the variables and the attribute
    names, and reuploaded.

    I get the error: from log0

    Caused by: java.lang.NullPointerException

    WARNING: Error executing the script:
    null

    This is puzzling as the script works, but when uploaded , then downloaded from
    the wiki, it yields the error.

    maybe Völker has an idea.

     
  • Pilominco :
    I have sent you a private message with the script to test, but the message
    encoding messes the code up.

     
  • Ok, I got it to work : I left an accented character in the code; I also
    changed the CreateTodayGTD.groovy script

    Now, both should work; please download both and try again.

     
  • Predrag
    Predrag
    2012-01-10

    Dear Michel

    I closely follow all the posts of this topic because I am currently working on
    the Study Planner. This is the Add-on for Freeplane, which will help children
    organize their learning time.
    Can you please read my request on the forum under topic ,
    Pomodoro timer in Freeplane ( point 6. from pegi7)
    [https://sourceforge.net/projects/freeplane/forums/forum/758437/topic/4917123]
    (http://null)
    and if you have time, please could you help me resolve my problem.

    Thanks in advance
    Predrag
    P.S. If you can please send me script on my e-mail address pcuklin@gmail.com

     
  • Predrag,

    I didn't understand you request.
    May I suggest that you describe more thoroughly your request in a separate
    topic ?
    You should simply describe with words what you want to get, or your project so
    that we may better understand. Maybe add your ideas on how you imagine to use
    Yu's Pomodoro timer or the tracker

    GL to you.

    Michel.

     
  • Miguel Boyer
    Miguel Boyer
    2012-01-10

    Yiiihaaaa...
    Now it works. Great!
    Except for the "totalJournee". The node atribute for the day does not get
    updated like it does on the video.
    And 2 sugestions:

    (1) You should have the form of the tracker to be able to get minimized. If
    you work on the computer, you should be able to see the screen while you work.
    ;)

    (2) When running the script, the values should be updated from the nodes, so
    that you can close the map and open it again at a latter time should you have
    several periods of work during the same day!

    Both suggestions seem relatively easy to implement, and they would make the
    tracker more robust and flexible. :)

    Hey, good job so far. Thanks.
    m.

     
  • Miguel Boyer
    Miguel Boyer
    2012-01-10

    Hey Michel:
    Forget about my first suggestion. Just silly. You only need to minimize
    Freeplane itself, and if needed, open a second instance for your work. (Sorry
    about that.)
    About the second suggestion, i still think it is necessary.
    Thanks.