Author: esr
Date: Mon Oct 13 15:55:30 2008
New Revision: 30115

URL: http://svn.gna.org/viewcvs/wesnoth?rev=30115&view=rev
Log:
trackplacer: we can now write track files.

Modified:
    trunk/data/tools/trackplacer

Modified: trunk/data/tools/trackplacer
URL: 
http://svn.gna.org/viewcvs/wesnoth/trunk/data/tools/trackplacer?rev=30115&r1=30114&r2=30115&view=diff
==============================================================================
--- trunk/data/tools/trackplacer (original)
+++ trunk/data/tools/trackplacer Mon Oct 13 15:55:30 2008
@@ -12,7 +12,7 @@
 Can be started with a map image, in which case we're editing a new journey.
 Can be started with a track file. A track file is a text file interpreted
 line-by-line; each line is interpreted as whitespace-separated fields.
-The first field of the first line must be FILE, and the second field
+The first field of the first line must be MAP, and the second field
 of that line must be valid filename.  Subsequent lines must have three
 fields each: an action tag (JOURNEY, BATTLE, or REST) and two numeric
 coordinate fields.
@@ -21,7 +21,15 @@
 track. This program exists to visually edit journeys represented in track
 files.
 
+Normally, trackplacer assumes it is running within a Battle for
+Wesnoth source tree and changes directory to the root of the
+tree. Paths saved in track files are relative to the tree root. All
+pathnames in help and error messages are also relativized to that
+root.
+
 The -v option enables verbose logging to standard error.
+
+The -d option sets the root directory to use.
 
 The -h or -? options display this summary.
 """
@@ -37,11 +45,6 @@
 
 The Help button displays this message.
 '''
-
-# TODO:
-# 1. Test reading and writing of track files
-# 2. Write track-to-macro tool.
-# 3. Implement save-handler stub.
 
 import sys, os, exceptions, getopt
 
@@ -72,56 +75,61 @@
 # a well-defined center pixel.
 vision_distance = 12
 
-class ReadException(exceptions.Exception):
+class IOException(exceptions.Exception):
     "Exception thrown while reading a track file."
-    def __init__(self, message, filename, lineno=None):
+    def __init__(self, message, path, lineno=None):
         self.message = message
-        self.filename = filename
+        self.path = path
         self.lineno = lineno
 
 class JourneyTrack:
     "Represent a journey track on a map."
     def __init__(self):
-        self.filename = None   # Map background of the journey
+        self.mapfile = None    # Map background of the journey
         self.track = []                # List of (action, x, y) tuples
         self.modifications = 0
         self.initial_track = []
     def write(self, fp):
         "Record a journey track."
-        fp.write("FILE %s\n" % self.filename)
-        for location in self.track:
-            fp.write("%s %d %d\n" % location)
+        if fp.name.endswith(".trk"):
+            fp.write("MAP %s\n" % self.mapfile)
+            for location in self.track:
+                fp.write("%s %d %d\n" % location)
+        elif fp.name.endswith(".cfg"):
+            sys.stderr.write(".cfg eriting is not yet implemented.")
+        else:
+            raise IOException("File must have a .trk or .cfg extension.", 
fp.name)
     def read(self, fp):
         "Initialize a journey from map and track information."
         if type(fp) == type(""):
             try:
                 fp = open(fp)
             except IOError:
-                raise ReadException("Cannot read file.", fp)
+                raise IOException("Cannot read file.", fp)
         if self.track:
-            raise ReadException("Reading with track nonempty.", fp.name)
+            raise IOException("Reading with track nonempty.", fp.name)
         if fp.name.endswith(".png") or fp.name.endswith(".jpg"):
-            self.filename = fp.name
+            self.mapfile = fp.name
             return
         if not fp.name.endswith(".trk"):
-            raise ReadException("Cannot read this filetype.", fp.name)
+            raise IOException("Cannot read this filetype.", fp.name)
         header = fp.readline().split()
-        if header[0] != 'FILE':
-            raise ReadException("Missing FILE element.", fp.name, 1)
-        else:
-            self.filename = header[1]
+        if header[0] != 'MAP':
+            raise IOException("Missing MAP element.", fp.name, 1)
+        else:
+            self.path = header[1]
         while (i, line) in enumerate(fp):
             fields = line.split()
             if len(fields) != 3:
-                raise ReadException("Ill-formed track file line.", fp.name, 
i+1)
+                raise IOException("Ill-formed track file line.", fp.name, i+1)
             (tag, x, y) = fields
             if tag not in ("JOURNEY", "BATTLE", "REST"):
-                raise ReadException("Invalid tag field on track file line.", 
fp.name, i+1)
+                raise IOException("Invalid tag field on track file line.", 
fp.name, i+1)
             try:
                 x = int(x)
                 y = int(y)
             except ValuError:
-                raise ReadException("Invalid coordinate field.", fp.name, i+1)
+                raise IOException("Invalid coordinate field.", fp.name, i+1)
             self.initial_track.append((tag, x, y))
         self.track = self.initial_track
     def has_unsaved_changes(self):
@@ -160,64 +168,70 @@
         else:
             return None
     def __str__(self):
-        return self.filename + ": " + `self.track`
+        return self.mapfile + ": " + `self.track`
 
 class ModalFileSelector:
     def __init__(self, default, legend):
         self.default = default
-        self.filename = None
+        self.path = None
         # Create a new file selection widget
         self.filew = gtk.FileSelection(legend)
         self.filew.set_modal(True);
 
         self.filew.ok_button.connect("clicked", self.selection_ok)
         self.filew.cancel_button.connect("clicked", self.selection_canceled)
-        self.filew.set_filename(self.default)
+        if self.default:
+            self.filew.set_filename(self.default)
         self.filew.run()
 
     def selection_canceled(self, widget):
-        self.filename = None
+        self.path = None
         self.filew.destroy()
 
     def selection_ok(self, widget):
-        self.filename = self.filew.get_filename()
+        self.path = self.filew.get_filename()
+        if self.path.startswith(os.getcwd()):
+            self.path = self.path[len(os.getcwd())+1:]
         self.filew.destroy()
 
 class TrackEditorIcon:
-    def __init__(self, action, filename):
+    def __init__(self, action, path):
         self.action = action
         # We need an image for the toolbar...
         self.image = gtk.Image()
-        self.image.set_from_file(filename)
+        self.image.set_from_file(path)
         # ...and a pixbuf for drawing on the map with.
-        self.icon = gtk.gdk.pixbuf_new_from_file(filename)
+        self.icon = gtk.gdk.pixbuf_new_from_file(path)
         self.icon_width = self.icon.get_width()
         self.icon_height = self.icon.get_height()
 
 class TrackEditor:
-    def __init__(self, filename=None, verbose=False):
+    def __init__(self, path=None, verbose=False):
         self.verbose = verbose
         # Initialize our info about the map and track 
         self.journey = JourneyTrack()
-        self.journey.read(filename)
+        self.last_read = None
+        self.journey.read(path)
+        if path.endswith(".trk"):
+            self.last_read = path
         self.action = "JOURNEY"
         # Backing pixmap for drawing area
         self.pixmap = None
 
         # Grab the map into a pixmap
-        self.log("about to read map %s" % self.journey.filename)
+        self.log("about to read map %s" % self.journey.mapfile)
         try:
-            self.map = gtk.gdk.pixbuf_new_from_file(self.journey.filename)
+            self.map = gtk.gdk.pixbuf_new_from_file(self.journey.mapfile)
             self.map_width = self.map.get_width()
             self.map_height = self.map.get_height()
             self.map = self.map.render_pixmap_and_mask()[0]
-        except gtk.Gerror:
-            self.fatal_error("Error while reading background map %s" % 
self.journey.filename)
+        except gtk.gobject.Gerror:
+            self.fatal_error("Error while reading background map %s" % 
self.journey.mapfile)
         # Now get the icons we'll need for scribbling on the map with.
         self.action_dictionary = {}
         try:
-            for (action, filename) in icon_dictionary.items():
-                icon = TrackEditorIcon(action, filename)
+            for (action, path) in icon_dictionary.items():
+                icon = TrackEditorIcon(action, path)
                 self.log("%s icon has size %d, %d" % \
                          (action, icon.icon_width, icon.icon_height))
                 self.action_dictionary[action] = icon
@@ -294,7 +308,7 @@
         # A save button
         button = gtk.Button("Save")
         buttonbox.pack_end(button, expand=False, fill=False, padding=10)
-        #button.connect_object("clicked", self.save_handler, window)
+        button.connect_object("clicked", self.save_handler, window)
         button.show()
 
         # A help button
@@ -448,6 +462,46 @@
         w.run()
         w.destroy()
 
+    def save_handler(self, w):
+        "Save track data,"
+        if not self.journey.has_unsaved_changes():
+            w = gtk.MessageDialog(type=gtk.MESSAGE_INFO,
+                                  flags=gtk.DIALOG_DESTROY_WITH_PARENT,
+                                  buttons=gtk.BUTTONS_OK)
+            w.set_markup("You have no unsaved changes.")
+            w.run()
+            w.destroy()
+        else:
+            w = ModalFileSelector(default=self.last_read, legend="Save track 
to file")
+            if not w.path.endswith(".trk") and not w.path.endswith(".cfg"):
+                raise IOException("File must have a .trk or .cfg extension.", 
w.path)
+            if w.path != self.last_read and os.path.exists(w.path):
+                self.save_check = gtk.Dialog(title="Really overwrite?",
+                                             parent=None, 
+                                             flags=gtk.DIALOG_MODAL,
+                                             buttons=(gtk.STOCK_CANCEL, 
gtk.RESPONSE_REJECT,
+                                                      gtk.STOCK_OK, 
gtk.RESPONSE_ACCEPT))
+                label = gtk.Label("Overwrite existing data in %s?" % w.path)
+                self.save_check.vbox.pack_start(label)
+                label.show()
+                self.save_check.connect("response",
+                                        self.conditional_save_handler)
+                self.save_check.run()
+                # After conditional_save handler fires
+                if not self.save_confirm:
+                    return
+            self.log("Writing track data to %s" % w.path)
+            try:
+                fp = open(w.path, "w")
+            except IOError:
+                raise IOException("Cannot write file.", w.path)
+            self.journey.write(fp)
+            fp.close()
+
+    def conditional_save_handler(self, widget, id):
+        self.save_confirm = (id == gtk.RESPONSE_ACCEPT)            
+        self.save_check.destroy()
+
     def log(self, msg):
         "Notify user of error and die."
         if self.verbose:
@@ -479,25 +533,28 @@
     else:
         wesnoth.wmltools.pop_to_top("trackplacer")
     if arguments:
-        TrackEditor(filename=arguments[0], verbose=verbose)
+        try:
+            TrackEditor(path=arguments[0], verbose=verbose)
+        except IOException, e:
+            sys.stderr.write(e.message + "\n")
     else:
         while True:
             try:
                 selector = ModalFileSelector(default=default_map,
                                              legend="Track or map file to 
read")
-                if not selector.filename:
+                if not selector.path:
                     break
-                TrackEditor(selector.filename, verbose=verbose)
-            except ReadException, e:
+                TrackEditor(selector.path, verbose=verbose)
+            except IOException, e:
                 w = gtk.MessageDialog(type=gtk.MESSAGE_ERROR,
                                       flags=gtk.DIALOG_DESTROY_WITH_PARENT,
                                       buttons=gtk.BUTTONS_OK)
                 if e.lineno:
-                    errloc = '"%s", line %d:' % (e.filename, e.lineno)
+                    errloc = '"%s", line %d:' % (e.path, e.lineno)
                     # Emacs friendliness
                     sys.stderr.write(errloc + " " + e.message + "\n")
                 else:
-                    errloc = e.filename + ":"
+                    errloc = e.path + ":"
                 w.set_markup(errloc + "\n\n" + e.message)
                 w.run()
                 w.destroy()


_______________________________________________
Wesnoth-commits mailing list
[email protected]
https://mail.gna.org/listinfo/wesnoth-commits

Reply via email to