OSDN Git Service

portability: make filenames unicode
authorMartin Renold <martinxyz@gmx.ch>
Mon, 18 Oct 2010 13:01:24 +0000 (15:01 +0200)
committerMartin Renold <martinxyz@gmx.ch>
Mon, 18 Oct 2010 14:31:38 +0000 (16:31 +0200)
This fixes various problems on Windows with saving/loading files
with special characters. https://gna.org/bugs/?16109

Note that we pass unicode strings to os.* functions to get
back unicode filenames (instead of the encoding of the system).

brush names: utf8 --> unicode
group names: already unicode
layer names: utf8 --> unicode
bruspack filenames: broken --> unicode

gui/brushmanager.py
gui/brushselectionwindow.py
gui/dialogs.py
gui/filehandling.py
gui/main.py
mypaint.py

index ee0dda3..bf6b1a2 100644 (file)
@@ -42,11 +42,11 @@ def parse_order_conf(file_content):
     curr_group = FOUND_BRUSHES_GROUP
     lines = file_content.replace('\r', '\n').split('\n')
     for line in lines:
-        name = line.strip()
+        name = unicode(line.strip(), 'utf-8')
         if name.startswith('#') or not name:
             continue
         if name.startswith('Group: '):
-            curr_group = unicode(name[7:], 'utf-8')
+            curr_group = name[7:]
             if curr_group not in groups:
                 groups[curr_group] = []
             continue
@@ -98,7 +98,7 @@ class BrushManager:
     def load_groups(self):
         for i in range(10):
             c = ManagedBrush(self)
-            c.name = 'context%02d' % i
+            c.name = u'context%02d' % i
             self.contexts.append(c)
 
         brush_by_name = {}
@@ -173,7 +173,9 @@ class BrushManager:
             # slashes for subirectories on all platforms.
             path += '/'
             l = []
+            assert isinstance(path, unicode) # make sure we get unicode filenames 
             for name in os.listdir(path):
+                assert isinstance(name, unicode)
                 if name.endswith('.myb'):
                     l.append(name[:-4])
                 elif os.path.isdir(path+name):
@@ -199,6 +201,9 @@ class BrushManager:
     def import_brushpack(self, path,  window):
         zip = zipfile.ZipFile(path)
         names = zip.namelist()
+        # zipfile does utf-8 decoding on its own; this is just to make
+        # sure we have only unicode objects as brush names.
+        names = [s.decode('utf-8') for s in names]
 
         readme = None
         if 'readme.txt' in names:
@@ -216,7 +221,7 @@ class BrushManager:
 
         # Validate file content. The names in order.conf and the
         # brushes found in the zip must match. This should catch
-        # encoding screwups, everything is supposed to be utf-8.
+        # encoding screwups, everything should be an unicode object.
         for brush in new_brushes:
             assert brush + '.myb' in names, 'invalid brushpack: brush %r in order.conf does not exist in zip' % brush
         for name in names:
@@ -255,8 +260,18 @@ class BrushManager:
 
             for brushname in brushes:
                 # extract the brush from the zip
-                myb_data = zip.read(brushname + '.myb')
-                preview_data = zip.read(brushname + '_prev.png')
+                assert (brushname + '.myb') in zip.namelist()
+                # looks like we need to encode to utf-8 again... bug in zipfile,
+                # which handles unicode fine otherwise...
+                brushname_utf8 = brushname.encode('utf-8')
+                try:
+                    myb_data = zip.read(brushname + '.myb')
+                except KeyError:
+                    myb_data = zip.read(brushname_utf8 + '.myb')
+                try:
+                    preview_data = zip.read(brushname + '_prev.png')
+                except KeyError:
+                    preview_data = zip.read(brushname_utf8 + '_prev.png')
                 # in case we have imported that brush already in a previous group, but decided to rename it
                 if brushname in renamed_brushes:
                     brushname = renamed_brushes[brushname]
@@ -322,7 +337,7 @@ class BrushManager:
             prefix = brush.get_fileprefix()
             zip.write(prefix + '.myb', brush.name + '.myb')
             zip.write(prefix + '_prev.png', brush.name + '_prev.png')
-            order_conf += brush.name + '\n'
+            order_conf += brush.name.encode('utf-8') + '\n'
         zip.writestr('order.conf', order_conf)
         zip.close()
 
@@ -342,7 +357,7 @@ class BrushManager:
         for group, brushes in self.groups.iteritems():
             f.write('Group: %s\n' % group.encode('utf-8'))
             for b in brushes:
-                f.write(b.name + '\n')
+                f.write(b.name.encode('utf-8') + '\n')
         f.close()
 
     def select_brush(self, base_brush=None, settings_str=None):
@@ -452,12 +467,13 @@ class ManagedBrush(object):
         if not self.name:
             i = 0
             while 1:
-                self.name = '%s%03d' % (prefix, i)
+                self.name = u'%s%03d' % (prefix, i)
                 a = os.path.join(self.bm.user_brushpath, self.name + '.myb')
                 b = os.path.join(self.bm.stock_brushpath, self.name + '.myb')
                 if not os.path.isfile(a) and not os.path.isfile(b):
                     break
                 i += 1
+        assert isinstance(self.name, unicode)
         prefix = os.path.join(self.bm.user_brushpath, self.name)
         if saving: 
             if '/' in self.name:
index d45b47c..725e8c5 100644 (file)
@@ -249,7 +249,7 @@ class GroupSelector(gtk.DrawingArea):
         for group in all_groups:
             group_label = brushmanager.translate_group_name(group)
             u = pad_s + group_label + pad_s
-            s = u.encode('utf8')
+            s = u.encode('utf-8')
             idx_start = idx
             for c in s:
                 self.idx2group[idx] = group
@@ -280,7 +280,7 @@ class GroupSelector(gtk.DrawingArea):
             attr.insert(pango.AttrForeground(c.red, c.green, c.blue, idx_start, idx))
 
             text += u + sp_s
-            idx += len(sp_s.encode("utf8"))
+            idx += len(sp_s.encode("utf-8"))
 
         layout.set_text(text)
         layout.set_attributes(attr)
index 12c2f33..783c882 100644 (file)
@@ -58,7 +58,7 @@ def ask_for_name(widget, title, default):
     else:
         result = None
     d.destroy()
-    return result
+    return result.decode('utf-8')
 
 def error(widget, message):
     window = widget.get_toplevel()
@@ -186,7 +186,7 @@ def open_dialog(title, window, filters):
 
     result = (None, None)
     if dialog.run() == gtk.RESPONSE_OK:
-        filename = dialog.get_filename()
+        filename = dialog.get_filename().decode('utf-8')
         file_format = None
         for i, (_, pattern) in enumerate(filters):
             if fnmatch(filename, pattern):
@@ -220,7 +220,7 @@ def save_dialog(title, window, filters, default_format=None):
 
     result = (None, None)
     while dialog.run() == gtk.RESPONSE_OK:
-        filename = dialog.get_filename()
+        filename = dialog.get_filename().decode('utf-8')
         file_format = None
         for i, (_, pattern) in enumerate(filters):
             if fnmatch(filename, pattern):
index 7ccc2e9..f24fcbf 100644 (file)
@@ -164,6 +164,7 @@ class FileHandler(object):
         dialog = self.save_dialog
         filename = dialog.get_filename()
         if filename:
+            filename = filename.decode('utf-8')
             filename, ext = os.path.splitext(filename)
             if ext:
                 saveformat = self.saveformat_combo.get_active()
@@ -253,6 +254,7 @@ class FileHandler(object):
     def update_preview_cb(self, file_chooser, preview):
         filename = file_chooser.get_preview_filename()
         if filename:
+            filename = filename.decode('utf-8')
             pixbuf = helpers.get_freedesktop_thumbnail(filename)
             if pixbuf:
                 # if pixbuf is smaller than 128px in width, copy it onto a transparent 128x128 pixbuf
@@ -283,7 +285,7 @@ class FileHandler(object):
         try:
             if dialog.run() == gtk.RESPONSE_OK:
                 dialog.hide()
-                self.open_file(dialog.get_filename())
+                self.open_file(dialog.get_filename().decode('utf-8'))
         finally:
             dialog.destroy()
 
@@ -314,7 +316,7 @@ class FileHandler(object):
         try:
             # Loop until we have filename with an extension
             while dialog.run() == gtk.RESPONSE_OK:
-                filename = dialog.get_filename()
+                filename = dialog.get_filename().decode('utf-8')
                 name, ext = os.path.splitext(filename)
                 saveformat = self.saveformat_combo.get_active()
 
index 91adf80..1a50332 100644 (file)
@@ -33,9 +33,11 @@ def main(datapath, confpath):
         sys.stdout = sys.stderr = open(options.logfile, 'a', 1)
         print '--- mypaint log %s ---' % time.strftime('%F %T')
 
+    confpath = unicode(options.config, sys.getfilesystemencoding())
+
     def run():
         print 'confpath =', options.config
-        app = application.Application(datapath, options.config, args)
+        app = application.Application(datapath, confpath, args)
 
         # Recent gtk versions don't allow changing those menu shortcuts by
         # default. <rant>Sigh. This very useful feature used to be the
index 0debef7..7cccf59 100644 (file)
@@ -19,7 +19,8 @@ def get_paths():
     # note: some distros use lib64 instead, they have to edit this...
     lib_compiled='lib/mypaint/'
     
-    scriptdir=os.path.dirname(sys.argv[0])
+    arg0 = unicode(sys.argv[0], sys.getfilesystemencoding())
+    scriptdir=os.path.dirname(arg0)
 
     # this script is installed as $prefix/bin. We just need $prefix to continue.
     #pwd=os.getcwd() # why????
@@ -28,6 +29,7 @@ def get_paths():
 
     if os.path.basename(dir_install) == 'bin':
         prefix=os.path.dirname(dir_install)
+        assert isinstance(prefix, unicode)
         libpath=join(prefix, lib_shared)
         libpath_compiled = join(prefix, lib_compiled)
         sys.path.insert(0, libpath)
@@ -37,21 +39,23 @@ def get_paths():
         prefix=None
         # this is py2exe point of view, all executables in root of installdir
         # all path must be normalized to absolute path
-        libpath = os.path.abspath(os.path.dirname(os.path.realpath(sys.argv[0])))
+        libpath = os.path.abspath(os.path.dirname(os.path.realpath(arg0)))
         sys.path.insert(0, libpath)
         localepath = join(libpath,'share/locale')
     else:
         # we are not installed
-        prefix=None
-        libpath='.'
+        prefix = None
+        libpath = u'.'
         localepath = 'po'
 
+    assert isinstance(libpath, unicode)
+
     try: # just for a nice error message
         from lib import mypaintlib
     except ImportError:
         print
         print "We are not correctly installed or compiled!"
-        print 'script: "%s"' % sys.argv[0]
+        print 'script: "%s"' % arg0
         if prefix:
             print 'deduced prefix: "%s"' % prefix
             print 'lib_shared: "%s"' % libpath
@@ -65,12 +69,14 @@ def get_paths():
         print datapath
         raise sys.exit(1)
 
-    homepath =  os.path.expanduser('~')
+    homepath =  os.path.expanduser(u'~')
     if homepath == '~':
         confpath = join(prefix, 'UserData')
     else:
         confpath = join(homepath, '.mypaint/')
 
+    assert isinstance(datapath, unicode)
+    assert isinstance(confpath, unicode)
     return datapath, confpath, localepath
 
 def psyco_opt():