Source code for albow.file_dialogs

# -*- coding: utf-8 -*-
#
# Albow - File Dialogs
#
#-# Modified by D.C.-G. for translation purpose

"""
TODO:

* Implement Windows support.
"""

import os, sys
from pygame import event, image
from pygame.transform import scale
from pygame.locals import *
from albow.widget import Widget
from albow.dialogs import Dialog, ask, alert
from albow.controls import Label, Button, Image
from albow.extended_widgets import ChoiceButton
from albow.fields import TextFieldWrapped
from albow.layout import Row, Column
from albow.palette_view import PaletteView # @Unused
from albow.scrollpanel import ScrollPanel
from albow.theme import ThemeProperty
from translate import _
from tree import Tree
import logging
log = logging.getLogger(__name__)


DEBUG = True

if DEBUG:
    from albow.resource import get_image

[docs] def get_imgs(): """Load an return the images used as file and folder icons.""" print "*** MCEDIT DEBUG: file_dialog:", __file__ print "*** MCEDIT DEBUG: directory:", os.path.dirname(__file__) print "*** MCEDIT DEBUG: current directory:", os.getcwd() try: file_image = get_image('file.png', prefix='') folder_image = get_image('folder.png', prefix='') except Exception, e: print "MCEDIT DEBUG: Could not load file dialog images." print e from pygame import draw, Surface from pygame.locals import SRCALPHA from math import pi file_image = Surface((16, 16), SRCALPHA) file_image.fill((0,0,0,0)) draw.lines(file_image, (255, 255, 255, 255), False, [[3, 15], [3, 1], [13, 1]], 2) draw.line(file_image, (255, 255, 255, 255), [3, 7], [10, 7], 2) folder_image = Surface((16, 16), SRCALPHA) folder_image.fill((0,0,0,0)) draw.line(folder_image, (255, 255, 255, 255), [3, 15], [3, 1], 2) draw.arc(folder_image, (255, 255, 255, 255), [0, 1, 13, 15], 0, pi/1.9, 2) draw.arc(folder_image, (255, 255, 255, 255), [0, 1, 13, 15], 3*pi/2, 2*pi, 2) return file_image, folder_image
else: from directories import getDataDir if sys.platform in ('darwin', 'linux2'): print "*** MCEDIT DEBUG: file_dialog:", __file__ print "*** MCEDIT DEBUG: directory:", os.path.dirname(__file__) print "*** MCEDIT DEBUG: current directory:", os.getcwd() try: file_image = image.load('file.png') folder_image = image.load('folder.png') except Exception, e: print "MCEDIT DEBUG: Could not load file dialog images." print e from pygame import draw, Surface from pygame.locals import SRCALPHA from math import pi file_image = Surface((16, 16), SRCALPHA) file_image.fill((0,0,0,0)) draw.lines(file_image, (255, 255, 255, 255), False, [[3, 15], [3, 1], [13, 1]], 2) draw.line(file_image, (255, 255, 255, 255), [3, 7], [10, 7], 2) folder_image = Surface((16, 16), SRCALPHA) folder_image.fill((0,0,0,0)) draw.line(folder_image, (255, 255, 255, 255), [3, 15], [3, 1], 2) draw.arc(folder_image, (255, 255, 255, 255), [0, 1, 13, 15], 0, pi/1.9, 2) draw.arc(folder_image, (255, 255, 255, 255), [0, 1, 13, 15], 3*pi/2, 2*pi, 2) else: # windows file_image = image.load(os.path.join(getDataDir(), 'file.png')) folder_image = image.load(os.path.join(getDataDir(), 'folder.png'))
[docs]class DirPathView(Widget): def __init__(self, width, client, **kwds): Widget.__init__(self, **kwds) self.set_size_for_text(width) self.client = client
[docs] def draw(self, surf): frame = self.get_margin_rect() image = self.font.render(self.client.directory, True, self.fg_color) tw = image.get_width() mw = frame.width if tw <= mw: x = 0 else: x = mw - tw surf.blit(image, (frame.left + x, frame.top))
[docs]class FileListView(ScrollPanel): def __init__(self, width, client, **kwds): font = self.predict_font(kwds) h = font.get_linesize() d = 2 * self.predict(kwds, 'margin') kwds['align'] = kwds.get('align', 'l') ScrollPanel.__init__(self, inner_width=width, **kwds) if DEBUG: file_image, folder_image = get_imgs() self.icons = {True: scale(folder_image, (self.row_height, self.row_height)), False: scale(file_image, (self.row_height, self.row_height))} self.client = client self.names = []
[docs] def update(self): client = self.client dir = client.directory def filter(name): path = os.path.join(dir, name) return os.path.isdir(path) or self.client.filter(path) try: content = os.walk(dir) for a, dirnames, filenames in content: dirnames.sort() filenames.sort() break try: self.names = [unicode(name, 'utf-8') for name in dirnames + filenames if filter(name)] except: self.names = [name for name in dirnames + filenames if filter(name)] except EnvironmentError, e: alert(u"%s: %s" % (dir, e)) self.names = [] self.rows = [Row([Image(self.icons[os.path.isdir(os.path.join(dir, a))]), Label(a, margin=0)], margin=0, spacing=2) for a in self.names] self.selected_item_index = None self.scroll_to_item(0)
[docs] def scroll_to_item(self, *args, **kwargs): self.scrollRow.scroll_to_item(*args, **kwargs)
[docs] def num_items(self): return len(self.names)
[docs] def click_item(self, item_no, e): self.selected_item_index = item_no ScrollPanel.click_item(self, item_no, e) if e.num_clicks == 2: self.client.dir_box_click(True)
[docs] def item_is_selected(self, item_no): return item_no == self.selected_item_index
[docs] def get_selected_name(self): sel = self.selected_item_index if sel is not None: return self.names[sel] else: return ""
[docs]def get_platform_root_dir(): #-# Rework this in order to mimic the OSs file chooser behaviour. #-# Need platform/version specific code... return '/'
[docs]class FSTree(Tree): def __init__(self, client, *args, **kwargs): kwargs['draw_zebra'] = False self.client = client self.directory = get_platform_root_dir() self.content = content = os.walk(self.directory) if client is not None and hasattr(client, 'directory'): self.directory = client.directory self.directory = kwargs.pop('directory', self.directory) self.data = data = {} d = {} for dirpath, dirnames, filenames in content: for name in dirnames: d[name] = self.parse_path(name, os.path.join(dirpath, name)) data[dirpath] = d break kwargs['data'] = data Tree.__init__(self, *args, **kwargs) del self.menu self.set_directory(self.directory)
[docs] def show_menu(self, *args, **kwargs): return
[docs] def set_directory(self, directory): self.diretory = directory self.deployed = [] splitted_path = directory.split(os.sep) while '' in splitted_path: splitted_path.remove('') splitted_path.insert(0, '/') d = self.data path = "" while splitted_path: name = splitted_path.pop(0) path = os.path.join(path, name) d[name] = self.parse_path(name, path) rows = self.build_layout() i = 0 for row in rows: if row[3] == name and self.get_item_path(row) in directory: self.deployed.append(row[6]) self.clicked_item = row rows[i + 1:] = self.build_layout()[i + 1:] if directory == self.get_item_path(row): self.treeRow.scroll_to_item(rows.index(row)) self.selected_item_index = rows.index(row) self.selected_item = row break i += 1 d = d[name]
[docs] def parse_path(self, name, path): #!# The log.debug() and print stuff in there are intended to fix some OSX issues. #!# Please do not strip them out. -- D.C.-G. # log.debug('FSTree.parse_path') # log.debug(' path: %s\n length: %d'%(repr(path), len(path))) # print ' path: %s\n length: %d'%(repr(path), len(path)) # log.debug(' path: %s\n length: %d'%(repr(path), len(path))) # if len(path) < 1: print ' ! ! ! ^ ^ ^ ! ! !' # if len(path) < 1: log.debug(' ! ! ! ^ ^ ^ ! ! !') content = os.walk(path) data = {} d = data for a, folders, b in content: # log.debug(' a: %s\n length: %d'%(repr(a), len(a))) # print ' a: %s\n length: %d'%(repr(a), len(a)) # log.debug(' a: %s\n length: %d'%(repr(a), len(a))) # if len(a) < 1: print ' ! ! ! ^ ^ ^ ! ! !' # if len(a) < 1: log.debug(' ! ! ! ^ ^ ^ ! ! !') d = {} for folder in folders: # log.debug(' folder: %s\n length: %d'%(repr(folder), len(folder))) # print ' folder: %s\n length: %d'%(repr(folder), len(folder)) # log.debug(' folder: %s\n length: %d'%(repr(folder), len(folder))) # if len(folder) < 1: print ' ! ! ! ^ ^ ^ ! ! !' # if len(folder) < 1: log.debug(' ! ! ! ^ ^ ^ ! ! !') if type(folder) == str: folder = unicode(folder, 'utf-8') d[folder] = {} if type(a) == str: a = unicode(a,'utf-8') cont = os.walk(os.path.join(a, folder)) for _a, fs, _b in cont: for f in fs: # log.debug(' f: %s\n length: %d'%(repr(f), len(f))) # print ' f: %s\n length: %d'%(repr(f), len(f)) # log.debug(' f: %s\n length: %d'%(repr(f), len(f))) # if len(f) < 1: print ' ! ! ! ^ ^ ^ ! ! !' # if len(f) < 1: log.debug(' ! ! ! ^ ^ ^ ! ! !') if type(f) == str: d[folder][unicode(f, 'utf-8')] = {} else: d[folder][f] = {} break break return d
[docs] def get_item_path(self, item): path_list = [] if item is not None: id = item[6] parents = [item] while id != 1: item = self.get_item_parent(parents[-1]) if item is None: break id = item[6] parents.append(item) parents.reverse() path_list = [a[3] for a in parents] path = '/' for name in path_list: path = os.path.join(path, name) return path
[docs] def deploy(self, id): path = self.get_item_path(self.clicked_item) self.clicked_item[9] = self.parse_path(self.clicked_item[3], path) Tree.deploy(self, id)
[docs] def select_item(self, n): Tree.select_item(self, n) self.client.directory = self.get_item_path(self.selected_item)
[docs]class FileDialog(Dialog): box_width = 450 default_prompt = None up_button_text = ThemeProperty("up_button_text") def __init__(self, prompt=None, suffixes=None, **kwds): Dialog.__init__(self, **kwds) label = None d = self.margin self.suffixes = suffixes or ("",) self.file_type = self.suffixes[0] up_button = Button(self.up_button_text, action=self.go_up) dir_box = DirPathView(self.box_width + 250, self) self.dir_box = dir_box top_row = Row([dir_box, up_button]) list_box = FileListView(self.box_width - 16, self) self.list_box = list_box tree = FSTree(self, inner_width=250, directory='/') self.tree = tree row = Row((tree, list_box), margin=0) ctrls = [top_row, row] prompt = prompt or self.default_prompt if prompt: label = Label(prompt) if suffixes: filetype_label = Label("File type", width=250) def set_file_type(): self.file_type = self.filetype_button.get_value() self.list_box.update() filetype_button = ChoiceButton(choices=self.suffixes, width=250, choose=set_file_type) self.filetype_button = filetype_button if self.saving: filename_box = TextFieldWrapped(self.box_width) filename_box.change_action = self.update_filename filename_box._enter_action = filename_box.enter_action filename_box.enter_action = self.enter_action self.filename_box = filename_box if suffixes: ctrls.append(Row([Column([label, filename_box], align='l', spacing=0), Column([filetype_label, filetype_button], align='l', spacing=0) ], ) ) else: ctrls.append(Column([label, filename_box], align='l', spacing=0)) else: if label: ctrls.insert(0, label) if suffixes: ctrls.append(Column([filetype_label, filetype_button], align='l', spacing=0)) ok_button = Button(self.ok_label, action=self.ok, enable=self.ok_enable) self.ok_button = ok_button cancel_button = Button("Cancel", action=self.cancel) vbox = Column(ctrls, align='l', spacing=d) vbox.topleft = (d, d) y = vbox.bottom + d ok_button.topleft = (vbox.left, y) cancel_button.topright = (vbox.right, y) self.add(vbox) self.add(ok_button) self.add(cancel_button) self.shrink_wrap() self._directory = None self.directory = os.getcwdu() #print "FileDialog: cwd =", repr(self.directory) ### if self.saving: filename_box.focus()
[docs] def get_directory(self): return self._directory
[docs] def set_directory(self, x): x = os.path.abspath(x) while not os.path.exists(x): y = os.path.dirname(x) if y == x: x = os.getcwdu() break x = y if self._directory != x: self._directory = x self.list_box.update() self.update()
directory = property(get_directory, set_directory)
[docs] def filter(self, path): if os.path.isdir(path) or path.endswith(self.file_type.lower()) or self.file_type == '.*': return True
[docs] def update(self): self.tree.set_directory(self.directory)
[docs] def update_filename(self): if self.filename_box.text in self.list_box.names: self.directory = os.path.join(self.directory, self.filename_box.text)
[docs] def go_up(self): self.directory = os.path.dirname(self.directory) self.list_box.scroll_to_item(0)
[docs] def dir_box_click(self, double): if double: name = self.list_box.get_selected_name() path = os.path.join(self.directory, name) suffix = os.path.splitext(name)[1] if suffix not in self.suffixes and os.path.isdir(path): self.directory = path else: self.double_click_file(name) self.update()
[docs] def enter_action(self): self.filename_box._enter_action() self.ok()
[docs] def ok(self): self.dir_box_click(True) #self.dismiss(True)
[docs] def cancel(self): self.dismiss(False)
[docs] def key_down(self, evt): k = evt.key if k == K_RETURN or k == K_KP_ENTER: self.dir_box_click(True) if k == K_ESCAPE: self.cancel()
[docs]class FileSaveDialog(FileDialog): saving = True default_prompt = "Save as:" ok_label = "Save"
[docs] def get_filename(self): return self.filename_box.text
[docs] def set_filename(self, x): dsuf = self.file_type if dsuf and x.endswith(dsuf): x = x[:-len(dsuf)] self.filename_box.text = x
filename = property(get_filename, set_filename)
[docs] def get_pathname(self): path = os.path.join(self.directory, self.filename_box.text) suff = self.file_type if suff and not path.endswith(suff): path = path + suff return path
pathname = property(get_pathname)
[docs] def double_click_file(self, name): self.filename_box.text = name
[docs] def ok(self): path = self.pathname if os.path.exists(path): answer = ask(_("Replace existing '%s'?") % os.path.basename(path)) if answer != "OK": return #FileDialog.ok(self) self.dismiss(True)
[docs] def update(self): FileDialog.update(self)
[docs] def ok_enable(self): return self.filename_box.text != ""
[docs]class FileOpenDialog(FileDialog): saving = False ok_label = "Open"
[docs] def get_pathname(self): name = self.list_box.get_selected_name() if name: return os.path.join(self.directory, name) else: return None
pathname = property(get_pathname) #def update(self): # FileDialog.update(self)
[docs] def ok_enable(self): path = self.pathname enabled = self.item_is_choosable(path) return enabled
[docs] def item_is_choosable(self, path): return bool(path) and self.filter(path)
[docs] def double_click_file(self, name): self.dismiss(True)
[docs]class LookForFileDialog(FileOpenDialog): target = None def __init__(self, target, **kwds): FileOpenDialog.__init__(self, **kwds) self.target = target
[docs] def item_is_choosable(self, path): return path and os.path.basename(path) == self.target
[docs] def filter(self, name): return name and os.path.basename(name) == self.target
[docs]def request_new_filename(prompt=None, suffix=None, extra_suffixes=None, directory=None, filename=None, pathname=None): if pathname: directory, filename = os.path.split(pathname) if extra_suffixes: suffixes = extra_suffixes else: suffixes = [] if suffix: suffixes = [suffix] + suffixes dlog = FileSaveDialog(prompt=prompt, suffixes=suffixes) if directory: dlog.directory = directory if filename: dlog.filename = filename if dlog.present(): return dlog.pathname else: return None
[docs]def request_old_filename(suffixes=None, directory=None): dlog = FileOpenDialog(suffixes=suffixes) if directory: dlog.directory = directory if dlog.present(): return dlog.pathname else: return None
[docs]def look_for_file_or_directory(target, prompt=None, directory=None): dlog = LookForFileDialog(target=target, prompt=prompt) if directory: dlog.directory = directory if dlog.present(): return dlog.pathname else: return None