site_manager.py
来自「CoralFTP是一款用Python语言编写的工作在GTK2环境下的FTP客户端」· Python 代码 · 共 920 行 · 第 1/3 页
PY
920 行
#!/usr/bin/env python# -*- coding: utf-8 -*-# Copyright (C) 1994 Ling Li## 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 2 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 Library General Public License for more details.## You should have received a copy of the GNU General Public License# along with this program; if not, write to the Free Software# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.import gobject, gtk, gtk.gdkfrom gobject import *from gtk import *from gtk.gdk import *import logging, os, re, string, xmlfrom xml.dom import minidomfrom coralftp_globals import *from site_info import *from utils import *# Site manager manages site address and individual options, the address and# options are stored in file ~/.coralftp/bookmarks.xml.# Sites are orgnized in tree structure. For quick connects, there is a folder# named Quick Connect in site manager to store all of them.defaultBookmarks = """<?xml version='1.0' encoding='UTF-8'?><ftp_bookmarks> <folder> <folder_name>Quick Connect</folder_name> <site> <site_name>localhost</site_name> <server_addr>localhost</server_addr> </site> </folder> <folder> <folder_name>Sites</folder_name> <folder> <folder_name>Linux</folder_name> <site> <site_name>ftp.linuxforum.net</site_name> <server_addr>ftp.linuxforum.net</server_addr> </site> <site> <site_name>debian.cn99.com</site_name> <server_addr>debian.cn99.com</server_addr> </site> </folder> </folder></ftp_bookmarks>"""class SiteManager(GObject): __gsignals__ = { # after-add-node method is invoked when new folder or new site is # created. The new created node is passed as signal param. 'after-add-node' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT,)), # before-delete-node method is invoked when existing folder or site # would be deleted. The node being deleted is passed as signal param. 'before-delete-node' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT,)), } data = SiteFolder() def __init__(self): self.__gobject_init__() self.add_folder('/Quick Connect') self.add_folder('/Sites') self.load() def get_site_by_id(self, id): if id == None or id == '': raise ValueError, "id should not be empty" folders = [self.data] while len(folders) > 0: folder = folders.pop() for name, item in folder.items(): if isinstance(item, SiteFolder): folders.append(item) else: if item['id'] == id: return item return None def find_folder_by_path(self, path, create = True): """This method is used to find a folder in the tree by the path of the node. If create is True and the folder is not exists, it would be create, and the existing or new created folder would be return. If create is False, value None would be returned indicating the absense.""" while path[0] == '/': path = path[1:] folder = self.data for part in string.split(path, '/'): if folder.has_key(part): folder = folder[part] if not isinstance(folder, SiteFolder): raise ValueError, folder else: if create: folder[part] = SiteFolder(name = part) folder = folder[part] else: return None return folder def get_path(self, node): """Get the path of a folder or a site. If the node can't be find, return None.""" def find_in_folder(folder, name = ""): for key, value in folder.items(): if value == node: return name + "/" + key if isinstance(value, SiteFolder): r = find_in_folder(value, key) if r != None: return name + "/" + r return None return find_in_folder(self.data) def add_folder(self, path): """add_folder is used to add a new folder to the path. The new created folder is returned.""" folder = self.find_folder_by_path(path, True) self.emit('after-add-node', folder) return folder def add_site(self, path, site_info): """add_site is used to add a existing SiteInfo object to the path.""" folder = self.find_folder_by_path(path, True) name = site_info['site_name'] folder[name] = site_info self.emit('after-add-node', site_info) return site_info def delete_folder(self, path): """Delete a folder.""" pos = path.rfind('/') parent_folder = self.find_folder_by_path(path[:pos], False) if parent_folder != None: name = path[pos+1:] if parent_folder.has_key(name): folder = parent_folder[name] self.emit('before-delete-node', folder) parent_folder.pop(name) return def delete_site(self, path): """Delete a site.""" pos = path.rfind('/') folder = self.find_folder_by_path(path[:pos], False) if folder != None: name = path[pos+1:] if folder.has_key(name): site = folder[name] self.emit('before-delete-node', site) folder.pop(name) return def save(self): """This method save all the bookmarks into the a XML file.""" def add_node(folder_node, data, path): if path != '': new_node = dom.createElement('folder_name') pos = path.rfind('/') folder_name = path[pos+1:] new_node.appendChild(dom.createTextNode(folder_name)) folder_node.appendChild(new_node) for key, value in data.items(): if isinstance(value, SiteFolder): new_node = dom.createElement('folder') folder_node.appendChild(new_node) add_node(new_node, value, path + '/' + key) elif isinstance(value, SiteInfo): new_node = dom.createElement('site') folder_node.appendChild(new_node) for attr_name, attr_value in value.items(): ele = dom.createElement(attr_name) ele.appendChild(dom.createTextNode( attr_value.__str__())) new_node.appendChild(ele) return config_dir = os.path.expanduser('~/.coralftp') if not os.path.exists(config_dir): os.mkdir(config_dir) if not os.path.isdir(config_dir): raise IOError, '%s is not a directory' % config_dir bookmark_file = config_dir + '/bookmarks.xml' impl = minidom.getDOMImplementation() dom = impl.createDocument(None, "ftp_bookmarks", None) add_node(dom.documentElement, self.data, '') f = file(bookmark_file, 'w') f.write(dom.toxml(encoding='UTF-8')) f.close() return def load(self): """This method read all bookmarks from a XML file.""" def get_text(nodelist): rc = '' for node in nodelist: if node.nodeType == node.TEXT_NODE: rc = rc + node.data return rc config_dir = os.path.expanduser('~/.coralftp') if not os.path.exists(config_dir): os.mkdir(config_dir) bookmark_file = os.path.join(config_dir, 'bookmarks.xml') if os.path.exists(bookmark_file): dom = xml.dom.minidom.parse(bookmark_file) else: dom = xml.dom.minidom.parseString(defaultBookmarks) assert dom.documentElement.tagName == 'ftp_bookmarks' nodes = [(dom.documentElement, ''),] while len(nodes) > 0: (node, path) = nodes.pop(0) for child_node in node.getElementsByTagName('folder'): if child_node.parentNode != node: continue ele = child_node.getElementsByTagName('folder_name')[0] child_name = get_text(ele.childNodes) nodes.append((child_node, path + '/' + child_name)) if path != '': folder = self.find_folder_by_path(path) for child_node in node.getElementsByTagName('site'): if child_node.parentNode != node: continue siteinfo = SiteInfo() siteinfo.from_xml_node(child_node) folder[siteinfo['site_name']] = siteinfo returngobject.type_register(SiteManager)class SiteManagerDialog: COL_NAME = 0 COL_SITEINFO = 1 COL_ICON = 2 # WIDGETS is used to represent relation between data and view. # The 1st element is key in the data dictionary. The 2nd element is # default value of data. The 3rd element is the name of widget and # the last one is the type of the widget. DATA_NAME = 0 DATA_DEFAULT = 1 WIDGET_NAME = 2 WIDGET_TYPE = 3 WIDGETS = ( ('site_name', '', 'entry_sitename', Entry), ('server_addr', '', 'entry_ipaddr', Entry), ('server_port', '21', 'spin_port', SpinButton), ('anonymous', 'True', 'cb_anonymous', CheckButton), ('username', '', 'entry_username', Entry), ('password', '', 'entry_password', Entry), ('remote_path', '', 'entry_remote_path', Entry), ('local_path', '', 'entry_local_path', Entry), ('remote_charset', 'GBK', 'entry_remote_charset', Entry), ('notes', '', 'tv_notes', TextView)) actions = None # __old_selected is used to save original selected element __old_selected = None __selected = None __node = None __parent = None __parent_node = None def __init__(self, coralftp): ACTIONS = { 'connect' : { 'sensitive' : FALSE, 'update' : self.on_connect_action_update, 'execute' : self.on_connect_action_execute}, 'apply' : { 'sensitive' : FALSE, 'update' : self.on_apply_action_update, 'execute' : self.on_apply_action_execute}, 'close' : { 'execute' : self.on_close_action_execute}, 'new_site' : { 'sensitive' : FALSE, 'update' : self.on_new_site_action_update, 'execute' : self.on_new_site_action_execute}, 'new_group' : { 'sensitive' : FALSE, 'update' : self.on_new_group_action_update, 'execute' : self.on_new_group_action_execute}, 'delete' : { 'sensitive' : FALSE,
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?