TODO.xml new files. TODO.xml is a first start on a roadmap towards

2000-12-27  Sven Neumann  <sven@gimp.org>

	* TODO.xml
	* docs/make-todo: new files. TODO.xml is a first start on a roadmap
	towards gimp-1.4. All new features and major changes need to be
	defined here to be accepted into the gimp-1.3 branch.
This commit is contained in:
Sven Neumann 2000-12-27 18:55:02 +00:00 committed by Sven Neumann
parent 7f29801363
commit c6ea8d673f
3 changed files with 537 additions and 0 deletions

View file

@ -1,3 +1,10 @@
2000-12-27 Sven Neumann <sven@gimp.org>
* TODO.xml
* docs/make-todo: new files. TODO.xml is a first start on a roadmap
towards gimp-1.4. All new features and major changes need to be
defined here to be accepted into the gimp-1.3 branch.
2000-12-27 Michael Natterer <mitch@gimp.org>
* app/gimpimage.c: gimp_image_merge_layers(): apply the layer mask

158
TODO.xml Normal file
View file

@ -0,0 +1,158 @@
<!-- Stuff that is scheduled to be done. Ideas do not go here, put
them into the old TODO file for now. -->
<!-- The following comment is not yet valid, since we have not yet
set up the website and updated the commit scripts. Please check
for parse errors anyway.
This is used to generate the online TODO list for GIMP using
the script docs/make-todo. Whenever a change to this file is
committed to CVS, the file is run through make-todo and the online
version updated. If you modify this file, you should check for
parse errors by running:
$ docs/make-todo TODO.xml > /dev/null
before committing, or you may screw up the online version -->
<todo logourl="wilber.png">
<title>GIMP TODO List</title>
<section>
<title>Objectification</title>
<entry size="small" difficulty="easy" status="0%" target="1.4">
<title>Generic GimpObject</title>
<description>
<p>
Directly derived from GObject, should probably have a name
argument.
</p>
</description>
<contact>
GIMP Developer List &lt;gimp-developer@xcf.berkeley.edu&gt;
</contact>
</entry>
<entry size="medium" difficulty="medium" status="0%" target="1.4">
<title>Cleanup existing internal objects</title>
<description>
<p>
GimpDrawable, Layer, GimpImage, GDisplay need to be redone as
proper GimpObjects. Write new objects (with proper names) and
port all stuff to the new objects incrementally.
</p>
</description>
<contact>
GIMP Developer List &lt;gimp-developer@xcf.berkeley.edu&gt;
</contact>
</entry>
<entry size="small" difficulty="medium" status="0%" target="1.4">
<title>Generic data structures</title>
<description>
<p>
Brushes, Patterns, Gradients should be derived from a GimpData
object.
</p>
</description>
<contact>
GIMP Developer List &lt;gimp-developer@xcf.berkeley.edu&gt;
</contact>
</entry>
<entry size="medium" difficulty="medium" status="0%" target="1.4">
<title>Generic object container(s)</title>
<description>
<p>
A GimpContainer that holds GimpObject objects. Comparable to
the GCimContainer, but no serialization for now. Should probably
dispatch "changed" (or other) signals from its children.
</p>
<p>
This container will be used for lists of brushes, patterns,
layers, channels, paths, ...
</p>
</description>
<contact>
GIMP Developer List &lt;gimp-developer@xcf.berkeley.edu&gt;
</contact>
</entry>
<entry size="medium" difficulty="medium" status="0%" target="1.4">
<title>Abstract GimpBrush object and derived brush types</title>
<description>
<p>
The GimpBrush object we have now is not a generic BrushProvider.
We need an abstract object to derive the different kinds of brushes
from (BrushPipes, parametric brushes, ...). It has to provide
methods for the PaintCore to transparently select and use the brush
data.
</p>
</description>
<contact>
GIMP Developer List &lt;gimp-developer@xcf.berkeley.edu&gt;
</contact>
</entry>
</section> <!-- Objectification -->
<section>
<title>User Interface</title>
<entry size="medium" difficulty="medium" status="0%" target="1.4">
<title>Abstract Container Views</title>
<description>
<p>
Views on data stored in a GimpContainer. The objects need to provide
hooks that this view can use to show data like patterns, brushes,
etc. in different views (list, grid, ...)
</p>
</description>
<contact>
GIMP Developer List &lt;gimp-developer@xcf.berkeley.edu&gt;
</contact>
</entry>
<entry size="big" difficulty="advanced" status="0%" target="1.4">
<title>Effect Preview Widget</title>
<description>
<p>
A generic preview widget with functions like scrolling and zooming
useable by effect filters. Should have adaptive supersampling,
progressive display (if possible) and other neat stuff.
</p>
</description>
<contact>
GIMP Developer List &lt;gimp-developer@xcf.berkeley.edu&gt;
</contact>
</entry>
</section> <!-- User Interface -->
<section>
<title>Internationalization</title>
<entry size="small" difficulty="medium" status="0%" target="1.4">
<title>Context-sensitive translations</title>
<description>
<p>
The same english string used in different contexts may need to
be translated differently in other languages. Think of a way to
implement this using gettext or come up with something better.
</p>
<p>
There is a patch with a possible solution on ftp.gimp.org,
but actually we'd like something cleaner if possible.
</p>
</description>
<url>ftp://ftp.gimp.org/pub/gimp/patches/gimp-chyla-20001207-0.patch</url>
<contact>
GIMP Developer List &lt;gimp-developer@xcf.berkeley.edu&gt;
</contact>
</entry>
</section> <!-- Internationalization -->
</todo>

372
docs/make-todo Executable file
View file

@ -0,0 +1,372 @@
#!/usr/bin/python
# Shamelessly stolen from the GTK+ source.
# Modified for The GIMP.
import xmllib;
import sys;
import string
import re
def html_subst(s):
if s.group(1) != None:
return s.group(0)
elif s.group(2) != None:
return '<a href="' + s.group(0) + '">' + s.group(0) + '</a>'
elif s.group(3) != None:
return '<a href="mailto:' + s.group(0) + '">' + s.group(0) + '</a>'
def htmlify(str):
return re.sub ("(<[^>]*>)|([ht|f]tp://[~.:/\w-]+)|([\w._!-]+@[\w_-]+).[\w._-]+", html_subst, str)
def bug_subst(s):
if s.group(1) != None:
return s.group(0)
else:
n = s.group(2)
return '<a href="http://bugs.gnome.org/db/%s/%s.html">#%s</a>' % (n[0:2], n, n)
def bugify(str):
str = re.sub ("(<[^>]*>)|#(\d+)", bug_subst, str)
return htmlify(str)
def make_id(str):
return re.sub ("[^a-z]","-", string.lower(str))
class ParseError (Exception):
pass
class Entry:
def __init__(self):
self.description = None
self.title = None
self.url = None
self.contact = None
self.bugs = None
def set_size(self, size):
size = string.lower(size)
if size == "small":
self.size = "Small"
elif size == "medium":
self.size = "Medium"
elif size == "big":
self.size = "Big"
else:
raise ParseError, 'size must be "small", "medium", or "big"'
def set_difficulty(self, difficulty):
difficulty = string.lower(difficulty)
if difficulty == "easy":
self.difficulty = "Easy"
elif difficulty == "medium":
self.difficulty = "Medium"
elif difficulty == "advanced":
self.difficulty = "Advanced"
else:
raise ParseError, 'difficulty must be "easy", "medium", or "advanced"'
def output(self):
if self.size == "Big":
bgcolor = "#88bb88"
elif self.size == "Medium":
bgcolor = "#b4d4b4"
else:
bgcolor = "#d0e0d0"
print '''<table cellspacing="0" cellpadding="2" width="97%%" border="0" bgcolor="#000000">
<tbody><tr><td colspan=2>
<table cellspacing="0" cellpadding="5" width="100%%" border="0" bgcolor="#ffffff">
<tbody>
<tr bgcolor="%s">
<td align="left" colspan="4"><font size="+1">%s</font></font></td>
</tr>
<tr bgcolor="%s">
<td align="left" width="20%%"><b>Size</b>: %s</td>
<td align="left" width="20%%"><b>Difficulty</b>: %s</td>
<td align="center" width="20%%"><b>Status</b>: %s</td>
<td align="right" width="20%%"><b>Target Version</b>: %s</td>
</tr>
<tr>
<td colspan=4>
%s
<table cellspacing="0" cellpadding="0">
<tbody>''' % (bgcolor, self.title, bgcolor, self.size, self.difficulty, self.status, self.target, htmlify(self.description))
if self.url != None:
print '''<tr><td width="0"><b>More Info</b>:</td>
<td>%s</td>
</tr>''' % htmlify (self.url)
if self.bugs != None:
print '''<tr><td width="0"><b>Bug Reports</b>:</td>
<td>%s</td>
</tr>''' % bugify (self.bugs)
if self.contact != None:
print '''<tr><td width="0"><b>Contact</b>:</td>
<td>%s</td>
</tr>''' % htmlify (self.contact)
print '''</tbody>
</table>
</td>
</tr>
</tbody></table>
</td></tr></tbody></table>
'''
class Section:
def __init__(self):
self.title = None
self.entries = []
def output(self):
print '<h2><a name="%s">%s</a></h2>' % (make_id(self.title), self.title)
first = 1
for entry in self.entries:
if not first:
print "<br>"
first = 0
entry.output()
class TodoParser (xmllib.XMLParser):
def __init__(self):
xmllib.XMLParser.__init__(self)
self.in_todo = 0
self.in_data = 0
self.data = ""
self.section = None
self.entry = None
self.logourl = None
self.title = None
self.sections = []
self.entitydefs = {}
def start_todo(self,attributes):
if self.in_todo:
raise ParseError, "<todo> tags may not be nested"
if attributes.has_key ("logourl"):
self.logourl = attributes["logourl"]
self.in_todo = 1
def end_todo(self):
self.in_todo = 0
def start_section(self,attributes):
if self.section:
raise ParseError, "<section> tags may not be nested"
self.section = Section()
def end_section(self):
if self.section.title == None:
raise ParseError, "<section> requires <title>"
self.sections.append(self.section)
self.section = None
def start_title(self,attributes):
if not self.in_todo:
raise ParseError, "<title> tag must be in <todo>, <section> or <entry>"
if self.in_data:
raise ParseError, "Unexpected <title> tag in content"
self.in_data = 1
def end_title(self):
self.in_data = 0
if self.entry:
self.entry.title = self.data
elif self.section:
self.section.title = self.data
else:
self.title = self.data
self.data = ""
def start_description(self,attributes):
if not self.entry:
raise ParseError, "<description> tag must be in <entry>"
if self.in_data:
raise ParseError, "Unexpected <description> tag in content"
self.in_data = 1
def end_description(self):
self.in_data = 0
self.entry.description = self.data
self.data = ""
def start_url(self,attributes):
if not self.entry:
raise ParseError, "<url> tag must be in <entry>"
if self.in_data:
raise ParseError, "Unexpected <url> tag in content"
self.in_data = 1
def end_url(self):
self.in_data = 0
self.entry.url = self.data
self.data = ""
def start_contact(self,attributes):
if not self.entry:
raise ParseError, "<contact> tag must be in <entry>"
if self.in_data:
raise ParseError, "Unexpected <contact> tag in content"
self.in_data = 1
def end_contact(self):
self.in_data = 0
self.entry.contact = self.data
self.data = ""
def start_bugs(self,attributes):
if not self.entry:
raise ParseError, "<bugs> tag must be in <bugs>"
if self.in_data:
raise ParseError, "Unexpected <bugs> tag in content"
self.in_data = 1
def end_bugs(self):
self.in_data = 0
self.entry.bugs = self.data
self.data = ""
def start_entry(self,attributes):
if not self.section:
raise ParseError, "<entry> tag must be in <section>"
if self.entry:
raise ParseError, "<entry> tags may not be nested"
self.entry = Entry()
if not attributes.has_key("size"):
raise ParseError, '"size" attribute required for entry'
self.entry.set_size(attributes["size"])
if not attributes.has_key("difficulty"):
raise ParseError, '"difficulty" attribute required for entry'
self.entry.set_difficulty(attributes["difficulty"])
if not attributes.has_key("status"):
raise ParseError, '"status" attribute (completion percentage) required for entry'
self.entry.status=attributes["status"]
if not attributes.has_key("target"):
raise ParseError, '"target" attribute (target version) required for entry'
self.entry.target=attributes["target"]
def end_entry(self):
if self.entry.title == None:
raise ParseError, "<entry> requires <title>"
if self.entry.description == None:
raise ParseError, "<entry> requires <description>"
self.section.entries.append(self.entry)
self.entry = None
def handle_data(self,data):
if self.in_data:
self.data = self.data + data
def unknown_starttag(self,tag,attributes):
if not self.in_data:
raise ParseError, "Unexpected start tag: " + tag
else:
self.data = self.data + "<" + tag
for (key,val) in attributes.items():
self.data = self.data + ' %s="%s"' % (key,val)
self.data = self.data + ">"
def unknown_endtag(self,tag):
if not self.in_data:
raise ParseError, "Unexpected end tag: " + tag
else:
self.data = self.data + "</%s>" % tag
def syntax_error(self, err):
if re.match("reference to unknown entity", err):
pass
else:
xmllib.XMLParser.syntax_error (self, err)
def unknown_entityref(self,ref):
if not self.in_data:
raise ParseError, "Unknown entity &" + ref + ";"
else:
self.data = self.data + "&" + ref + ";"
file = open(sys.argv[1])
parser = TodoParser()
lineno = 1
while 1:
line = file.readline()
if line == "":
break
try:
parser.feed(line)
except ParseError, err:
sys.stderr.write("Parse error at line " + `lineno` + ": " + err.__str__() + "\n")
sys.exit(1)
except RuntimeError, err:
sys.stderr.write(err.__str__() + "\n")
sys.exit(1)
lineno = lineno + 1
parser.close()
if parser.title == None:
sys.stderr.write ("<todo> Document must have a <title>\n")
sys.exit (1)
print '''<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN">
<html>
<head>
<title>%s</title>
</head>
<body bgcolor="#ffffff">
<table width="100%%" cellspacing="0" cellpadding="0" border="0">
<tbody>
<tr valign="top">
<td>
<h1>%s</h1>''' % (parser.title, parser.title)
for section in parser.sections:
ntasks = len(section.entries)
id = make_id (section.title)
if ntasks == 1:
print '<a href="#%s">%s</a> (1 item)<br>' % (id,section.title)
else:
print '<a href="#%s">%s</a> (%d items)<br>' % (id,section.title,ntasks)
print '''
</td>'''
if parser.logourl != None:
print ''' <td align="right">
<img src="%s" alt="Logo"></img>
</td>''' % parser.logourl
print '''
</tr>
</tbody>
</table>
'''
first = 1
for section in parser.sections:
if not first:
print "<br><br>"
first = 0
section.output()
print '''</body>
</html>'''