← Back to team overview

gtg-user team mailing list archive

Plugin to print a tasks list to a file

 

Hi everybody,

Firstly congratulations for this great little application. It s very very
useful for me.

The only problem I had is that my boss ask me at the end of the week an
activities report about what my team did and what is plan the upcoming week.
Unfortunately GTG doen't offer this "print feature" for the moment so i
developed a little plugin to do that. Basically it does :
- Export the tasks into a text file opened by gedit (or any other text
editor)
- You have the posibility to choose to print upcoming task only or done task
only or both

I'm really not a developper (first time i use python and gtk) so surely the
code is not very pretty, but it seems to work for me and that why i wanted
to share it with you.
The choice to export it to gedit is that sometimes I don t want to report
ALL the tasks written to my boss so with gedit I can re-arrange it,
copy/paste to thunderbird, etc... If you want to print from gedit it s
better to change the default size of font to 6 or 7 depending how many tasks
you have.

To install it you need the version 0.1.2-dev (installed with bzr branch
lp:gtg)
Than in gtg/GTG/plugins :
- copy printTasksToFile.gtg-plugin
And in gtg/GTG/plugins/printTasksToFile
- copy the 3 other files

Hope it could be useful to someone else,
cheers,

Benoit

Attachment: printTasksToFile.gtg-plugin
Description: Binary data

# -*- coding: utf-8 -*-
# Copyright (c) 2009 - Paulo Cabido <paulo.cabido@xxxxxxxxx>
#
# This program is free software: you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free Software
# Foundation, either version 3 of the License, or (at your option) any later
# version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
# details.
#
# You should have received a copy of the GNU General Public License along with
# this program.  If not, see <http://www.gnu.org/licenses/>.

import sys,os
sys.path.insert(0,os.getcwd())
#sys.path.insert(0,os.path.dirname(os.path.abspath(__file__)))
from printTasksToFile import pluginPrintTasksToFile

Attachment: printTasks.glade
Description: Binary data

# -*- coding: utf-8 -*-
# Copyright (c) 2009 - Paulo Cabido <paulo.cabido@xxxxxxxxx>
#
# This program is free software: you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free Software
# Foundation, either version 3 of the License, or (at your option) any later
# version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
# details.
#
# You should have received a copy of the GNU General Public License along with
# this program.  If not, see <http://www.gnu.org/licenses/>.

import os
import sys
import datetime
import time

from xml.dom import minidom
from time import strftime
from datetime import date


try:
 	import pygtk
  	pygtk.require("2.0")
except:
  	pass
try:
	import gtk
  	import gtk.glade
except:
	sys.exit(1)


class pluginPrintTasksToFile:


    
    def __init__(self):
        self.menu_item = gtk.MenuItem("Print a list of tasks to a text file")
        self.menu_item.connect('activate', self.onTesteMenu)
        self.tb_button = gtk.ToolButton(gtk.STOCK_PRINT)
        self.tb_button.set_label("Print to file")
        self.tb_button.connect('clicked', self.onTbButton)
    	self.printString = ""

    def printButton_clicked(self, source=None, event=None):
        self.print_to_file(self.wTree.get_widget('programToExport').get_text())
	return True 

    # plugin engine methods	
    def activate(self, plugin_api):
	# add a menu item to the menu bar
        plugin_api.add_menu_item(self.menu_item)
        # saves the separator's index to later remove it
        self.separator = plugin_api.add_toolbar_item(gtk.SeparatorToolItem())
        # add a item (button) to the ToolBar
        plugin_api.add_toolbar_item(self.tb_button)
	# Get the requester and the plugin API
	self.req = plugin_api.get_requester()
	self.papi = plugin_api


    def onTaskOpened(self, plugin_api):
	# add a item (button) to the ToolBar
        self.tb_Taskbutton = gtk.ToolButton(gtk.STOCK_EXECUTE)
        self.tb_Taskbutton.connect('clicked', self.onTbTaskButton, plugin_api)
        plugin_api.add_task_toolbar_item(gtk.SeparatorToolItem())
        plugin_api.add_task_toolbar_item(self.tb_Taskbutton)
		
    def deactivate(self, plugin_api):
        plugin_api.remove_menu_item(self.menu_item)
        plugin_api.remove_toolbar_item(self.tb_button)
        plugin_api.remove_toolbar_item(None, self.separator)
		
    def loadDialog(self):
	# Loading of the GUI interface
        path = os.path.dirname(os.path.abspath(__file__))
        glade_file = os.path.join(path, "printTasks.glade")
        self.wTree = gtk.glade.XML(glade_file, "printTasks")
        self.dialog = self.wTree.get_widget("printTasks")
        events = { 'on_printButton_clicked': self.printButton_clicked,
                   'delete': self.close_dialog               }
        self.wTree.signal_autoconnect(events)
        #self.dialog.connect("delete_event", self.close_dialog)
        #self.dialog.connect("response", self.close_dialog)        
        self.dialog.show_all()




    ################################## 
    # Export to FILE
    def print_to_file(self, programToExport):
	# Initiation of the string to export/print
	self.printString = ""

	# Print the "header of the document"
	self.printString = self.printString + "\n--- DATE OF REPORT: "+strftime("%Y-%m-%d %H:%M:%S")+" ---"

	# Print the active tasks if checked
	if (self.wTree.get_widget('checkActiveTasks').get_active()):
		self.print_active_tasks()

	# Print the done tasks if checked
	if (self.wTree.get_widget('checkDoneTasks').get_active()):
		self.print_done_tasks()

	fileName = "tasks_report.txt"
	FILE = open(fileName,"w")
	FILE.writelines(self.printString)
	FILE.close()
	# Launch the system command to open the text file
	ret = os.system(programToExport + " " + fileName + " &")
	#print "\n\n ***** "+str(ret)+" ****\n\n"
	#if (ret != 0):
	#	self.wTree.get_widget('errorLbl').set_text("Error with the command")
	#else:
	self.dialog.destroy()

	
    
    ################################## 
    # Print all active tasks
    def print_active_tasks(self):
	self.printString = self.printString + "\n\n\n\n\n"
	self.printString = self.printString + "################################################################# \n"
	self.printString = self.printString + "################################################################# \n"
	self.printString = self.printString + "####                                                         #### \n"
	self.printString = self.printString + "####                      INCOMING TASKS                     #### \n"
	self.printString = self.printString + "####                                                         #### \n"
	self.printString = self.printString + "################################################################# \n"
	self.printString = self.printString + "################################################################# \n"
	self.printString = self.printString + "\n\n"
	rootTaskNumber = 0
	# Get all tasks
        for tid in self.papi.get_all_tasks():
	       	task = self.req.get_task(tid)
		# We only want the "root" tasks which are active
		if (not task.has_parents()) and (task.status != task.STA_DONE) :	
			rootTaskNumber = rootTaskNumber + 1
			# Print the root task
			self.print_rootTask(task)
			# Print the subtasks of this root task (recursively)
			self.print_subtasks(task, 0, rootTaskNumber)


    ##########################################
    # Print of root tasks
    def print_rootTask(self, task):
	taskTitle = task.get_title()
	# Write the TITLE of the task
	self.printString = self.printString + "\n\n\n**"+ "*"*len(taskTitle) +"**\n"
	self.printString = self.printString + "* "+taskTitle+" *\n"
	self.printString = self.printString + "**"+ "*"*len(taskTitle) +"**"
	# Create the tags string
	tagsStr = "* Tags:"
	for t in task.get_tags():
		tagsStr = tagsStr + t.get_name()
	tagsStr = tagsStr.replace("@", " ") + " "
	# Create the dates string
	datesStr = "* Start: "
	datesStr = datesStr + self.get_start_date(task)
	datesStr = datesStr + " * End: "
	datesStr = datesStr + self.get_due_date(task)
	datesStr = datesStr + " *"
	# Write the TAGS and DATES of the task
	endDelimiter = len(tagsStr+datesStr)
	if (endDelimiter > (len(taskTitle)+4)):
		self.printString = self.printString+"*"*(endDelimiter-len(taskTitle)-4)+"\n" 
		self.printString = self.printString + tagsStr + datesStr + "\n"
	else:
		self.printString = self.printString + "\n" + tagsStr + datesStr + "\n"
	self.printString = self.printString + "*"*(endDelimiter) + "\n"
	# Write TEXT DESCRIPTION of the task
	self.printString = self.printString + self.clean_task_text(task)



    ##########################################
    # Print the active subtasks 
    def print_subtasks(self, rootTask, taskLevel, rootTaskNumber):
	numSousTache = 0
	for subtask in rootTask.get_subtasks():
		# Print only active tasks
		if (subtask.status != subtask.STA_DONE):
			numSousTache = numSousTache+1				
			subTaskTitle = str(rootTaskNumber) + "." + str(numSousTache) + ") " + subtask.get_title()
			self.printString = self.printString + "\n" + "\t"*taskLevel + subTaskTitle
			tagsStr = ""		
			for t in subtask.get_tags():
				tagsStr = tagsStr + t.get_name()
			tagsStr = tagsStr.replace("@", " ")
	 		self.printString = self.printString + " (Tags: "+tagsStr+" | Start: "+self.get_start_date(subtask)+" | End: "+self.get_due_date(subtask)+")\n"
			self.printString = self.printString  + "\t"*taskLevel + "=" * len(subTaskTitle) +"\n"
			text = "\t"*taskLevel + self.clean_task_text(subtask)
			text = text.replace("\n", "\n"+"\t"*taskLevel)
			self.printString = self.printString + text
		#recursive loop
		self.print_subtasks(subtask, taskLevel+1, str(str(rootTaskNumber)+"."+str(numSousTache)))


    ################################## 
    # Print all done maintasks, organized by category 
    def print_done_tasks(self):
	self.printString = self.printString + "\n\n\n\n\n"
	self.printString = self.printString + "################################################################# \n"
	self.printString = self.printString + "################################################################# \n"
	self.printString = self.printString + "####                                                         #### \n"
	self.printString = self.printString + "####                        DONE TASKS                       #### \n"
	self.printString = self.printString + "####                                                         #### \n"
	self.printString = self.printString + "################################################################# \n"
	self.printString = self.printString + "################################################################# \n"
	self.printString = self.printString + "\n\n"
	rootTaskNumber = 0

        for tid in self.req.ds.all_tasks():
		task = self.req.get_task(tid)
		# Print only done tasks
		if not task.has_parents():	
			#print("\n **** Tache principale : "+task.get_title())	
			rootTaskNumber = rootTaskNumber + 1
			self.print_done_task(task, 0, rootTaskNumber)
			#self.printString = self.printString + "\n **** Tache principale : " + 
			self.print_done_subtasks(task, 0, rootTaskNumber)


    ################################## 
    # Print ONE done task
    def print_done_task(self, task, numSousTache, rootTaskNumber):
	#Test to see if the task is not too old to be displayed (7 days for default)
	#self.printString = self.printString + "\n" + task.get_title() + "  ----  " + str(task.status) + "  ****  "+ str(task.has_parents())
	if (task.status == task.STA_DONE):
		daysBack = self.wTree.get_widget('daysBack').get_text()
		dateDone = datetime.datetime(*time.strptime(task.get_closed_date(), "%Y-%m-%d")[0:5])
		dateNow  = datetime.datetime.today()
		if (dateDone >= (dateNow-datetime.timedelta(days=int(daysBack)))):
			#numSousTache = rootTask.get_task_index(task.get_id())+1
			taskTitle = "\n" + str(rootTaskNumber) + "." + str(numSousTache) + ") " + task.get_title()
			self.printString = self.printString + "\n" + taskTitle		
			tagsStr = ""		
			for t in task.get_tags():
				tagsStr = tagsStr + t.get_name()
			tagsStr = tagsStr.replace("@", " ")
	 		self.printString = self.printString + " (Tags: "+tagsStr+" | Done: "+task.get_closed_date()+")\n"
			self.printString = self.printString  + "=" * len(str(taskTitle)) +"\n"
			text = self.clean_task_text(task)
			self.printString = self.printString + text


    ################################## 
    # Print all done subtasks
    def print_done_subtasks(self, rootTask, taskLevel, rootTaskNumber):
	numSousTache = 0
	for subtask in rootTask.get_subtasks():
		# Print only done tasks
		if (subtask.status == subtask.STA_DONE):
			#numSousTache = rootTask.get_task_index(subtask.get_id())+1
			numSousTache = numSousTache+1				
			self.print_done_task(subtask, numSousTache, rootTaskNumber)
		self.print_done_subtasks(subtask, taskLevel+1, str(str(rootTaskNumber)+"."+str(numSousTache)))



    ##########################################
    # Remove the XML tags from the task description
    # Remove also the subtasks enumeration (with the little array)
    def clean_task_text(self, task):
	text = task.get_text()
	#Clear the <content> tag
	text = text.replace("<content>", "")
	text = text.replace("</content>", "")
	#Clear the subtask lines (with the little arraw)
	text = text.replace("→", "")		
	while text.find("<subtask>")>=0:
		firstSubTask = text.find("<subtask>")-1
		endSubTask   = text.find("</subtask>")+len("</subtask>")+1
		text = text[0:firstSubTask] + text[endSubTask:]
	#Remove the tags
	while text.find("<tag>")>=0:
		firstSubTask = text.find("<tag>")
		endSubTask   = text.find("</tag>")+len("</tag>")+1
		text = text[0:firstSubTask] + text[endSubTask:]
	return text

    ################################## 
    # Return the start date, if no start date return "n/a"
    def get_start_date(self, subtask):
	if (subtask.get_start_date()==""):
		return "n/a"
	else:
		return subtask.get_start_date()

    ################################## 
    # Return the start date, if no start date return "n/a"
    def get_due_date(self, subtask):
	if (subtask.get_due_date()==""):
		return "n/a"
	else:
		return subtask.get_due_date()


    def close_dialog(self, widget, data=None):
    	self.dialog.destroy()
        return True    
	
	# plugin features
    def onTesteMenu(self, widget):
        self.loadDialog()
		
    def onTbButton(self, widget):
        self.loadDialog()
		
    def onTbTaskButton(self, widget, plugin_api):
        self.loadDialog()

	

Follow ups