[Clippy-commits] SF.net SVN: clippy:[9] clippy
Status: Pre-Alpha
Brought to you by:
edheldil
|
From: <edh...@us...> - 2010-01-07 23:35:48
|
Revision: 9
http://clippy.svn.sourceforge.net/clippy/?rev=9&view=rev
Author: edheldil
Date: 2010-01-07 23:35:31 +0000 (Thu, 07 Jan 2010)
Log Message:
-----------
Refactoring repo configuration
Replaced core with repo loader
New repo for art.gnome.org
Simplified assistant ui fiels a bit
Modified Paths:
--------------
Makefile
clippy/config.py
clippy/repositories/dia_shapes_repo.py
clippy/repositories/ghns_repo.py
clippy/repositories/local_dir_repo.py
clippy/repositories/ocal_repo.py
clippy/repositories/rest_repo.py
clippy/repository.py
clippy/ui/__init__.py
clippy/ui/assistant/app.py
clippy/ui/assistant/ui.py
clippy/ui/assistant/win_main.py
clippy/ui/shell/app.py
clippy/utils.py
setup.py
Added Paths:
-----------
clippy/loader.py
clippy/repositories/art_gnome_org_repo.py
Removed Paths:
-------------
clippy/core.py
Modified: Makefile
===================================================================
--- Makefile 2010-01-01 21:14:58 UTC (rev 8)
+++ Makefile 2010-01-07 23:35:31 UTC (rev 9)
@@ -10,7 +10,8 @@
all:
clean:
- -rm *~ *.pyc *.core *.tmp MANIFEST clippy/*~ clippy/*.pyc clippy/*/*~ clippy/*/*.pyc clippy/*/*/*~ clippy/*/*/*.pyc
+ -rm *~ *.pyc *.core *.tmp MANIFEST clippy/*~ clippy/*.pyc clippy/*/*~ clippy/*/*.pyc clippy/*/*/*~ clippy/*/*/*.pyc
+ -rm -rf build tmp
cleanrepo:
-rm ./tout/*
@@ -21,6 +22,9 @@
bdist:
python ./setup.py bdist
+install:
+ python ./setup.py install --prefix=tmp
+
dist:
tar cvzf $(FULLNAME).tar.gz $(SOURCES) $(DATA)
Modified: clippy/config.py
===================================================================
--- clippy/config.py 2010-01-01 21:14:58 UTC (rev 8)
+++ clippy/config.py 2010-01-07 23:35:31 UTC (rev 9)
@@ -15,12 +15,23 @@
def __init__ (self):
self.config = {}
+ self.dirty = False
+ self.user_config = None
self.createConfig ()
+
# FIXME: is it a good idea?
- atexit.register (self.writeConfigFile, self.CONFIG_FILE)
+ #atexit.register (self.write_user_config, self.CONFIG_FILE)
+ def read_file (self, filename):
+ cfg = ConfigFile ()
+ cfg.read (filename)
+ self.addConfig (cfg)
+ def write_user_config (self):
+ if self.user_config and self.dirty:
+ self.user_config.write ()
+
def createConfig (self):
try:
os.mkdir (self.CONFIG_DIR)
@@ -33,44 +44,7 @@
- def read (self, filename, config = None):
- if config is None:
- config = self.config
-
- try:
- fh = open (filename, 'r')
- except IOError:
- return False
- for line in fh:
- line = line.strip ()
- if line == '' or line.startswith ('#'):
- continue
-
- key, value = line.split ('=', 1)
- key = key.strip ()
- value = value.strip ()
-
- config[key] = value
-
- fh.close ()
- return True
-
-
- def write (self, filename):
- try:
- fh = open (filename + '.tmp', 'w')
-
- for key in sorted (self.config):
- fh.write ("%s = %s\n" %(key, str (self.config[key])))
-
- fh.flush ()
- fh.close ()
- os.rename (filename + '.tmp', filename)
- except IOError, e:
- print >>sys.stderr, "Error writing config file %s:" %filename, e
-
-
def get (self, key, default = None):
# FIXME: get rid of default value?
try:
@@ -89,11 +63,20 @@
# FIXME: meaningful exception?
self.config[key]
self.config[key] = value
+ # FIXME: set key in userconfig and make it dirty
+ def add (self, key, value):
+ if not key in self.config:
+ self.config[key] = value
def createKey (self, key, description, default):
self.config[key] = default
+ def addConfig (self, cfg):
+ if isinstance (cfg, ConfigFile):
+ cfg = cfg.config
+ for key, value in cfg.items ():
+ self.add (key, value)
# def getConfigTree (self, prefix):
# if not prefix.endswith ('.'):
@@ -107,3 +90,47 @@
# return res
+class ConfigFile (object):
+ def __init__ (self, **kw):
+ self.config = {}
+ self.filename = None
+
+ def read (self, filename):
+ try:
+ fh = open (filename, 'r')
+ except IOError:
+ return False
+
+ self.filename = filename
+
+ for line in fh:
+ line = line.strip ()
+ if line == '' or line.startswith ('#'):
+ continue
+
+ key, value = line.split ('=', 1)
+ key = key.strip ()
+ value = value.strip ()
+
+ self.config[key] = value
+
+ fh.close ()
+ return True
+
+
+ def write (self, filename=None):
+ if not filename:
+ filename = self.filename
+
+ try:
+ fh = open (filename + '.tmp', 'w')
+
+ for key in sorted (self.config):
+ fh.write ("%s = %s\n" %(key, str (self.config[key])))
+
+ fh.flush ()
+ fh.close ()
+ os.rename (filename + '.tmp', filename)
+ except IOError, e:
+ print >>sys.stderr, "Error writing config file %s:" %filename, e
+
Deleted: clippy/core.py
===================================================================
--- clippy/core.py 2010-01-01 21:14:58 UTC (rev 8)
+++ clippy/core.py 2010-01-07 23:35:31 UTC (rev 9)
@@ -1,105 +0,0 @@
-# -*-python-*-
-# vim: set ts=4 sw=4 expandtab:
-
-import os.path
-
-clippy_core = None
-
-def registerRepository (id, klass):
- clippy_core.registerRepository (id, klass)
-
-
-class Loader (object):
-
- repository_list = []
- repository_map = {}
-
-
- def __init__ (self):
- global clippy_core
- clippy_core = self
-
- def loadRepositories (self, repo_dir):
- import clippy.repositories
- self.importRepositoryClasses (os.path.dirname (clippy.repositories.__file__))
- #self.importRepositoryClasses (self.USER_REPO_DIR)
- try:
- self.loadRepositoryDefinitions (repo_dir, None)
- except:
- print "Skipping ", repo_dir
- pass
-
- def importRepositoryClasses (self, dir):
- for file in sorted (os.listdir (dir)):
- file, ext = os.path.splitext (file)
- if not ext.lower () in ['.py', '.pyc', '.pyo', '.pyw']:
- continue
-
- # FIXME: or use execfile()?
- exec 'import clippy.repositories.' + file
-
-
- def loadRepositoryDefinitions (self, dir, progress_fn):
- for file in sorted (os.listdir (dir)):
- if not file.endswith ('.cfg'):
- continue
-
- # FIXME: this prevents developer to supply their
- # own config class. Rather pass config class factory as an argument to this function
- config = config.Config ()
- config.read (os.path.join (dir, file))
- config = config.config # FIXME: ugly
-
- id = config['id']
- # FIXME: check that id is unique?
- klass = config['class']
- klass = self.getRepositoryClass (klass)
-
- # NOTE: the effect is that config keys defined in main config file
- # shadow those in a repo definition file and in a class.
- #for key, value in config.items ():
- # if key == 'id' or key == 'class':
- # continue
- #
- # key = 'repo.' + id + '.' + key
- # if not key in self.config:
- # #self.config[key] = value
- # pass
-
- self.registerRepository (id, klass, config)
- #yield True
- #yield False
-
-
- def registerRepository (self, id, klass, config = None):
- # This method is called from repository modules
-
- # get repo's config params.
- # merge forward duplicate config keys, i.e. (name, dir, name) becomes (name, dir) (FIXME: just merge?)
- # add config params to global config if they are not there yet
- # create instance and give it id and some ref to config
- # repo's __init__() sets attrs based on repo.<id>.xxxx
-
- params = klass.getConfigParams ()
- if config is None:
- config = {}
- for param in reversed (params):
- key = param[0]
- if not config.has_key (key):
- config[key] = param[4]
-
- Loader.repository_map[id] = (klass, config)
-
- def getRepositories (self):
- return self.repository_map
-
- def getRepository (self, id):
- klass, config = self.getRepositoryClass (id)
- repo = klass (id, config.copy ())
- return repo
-
-
- def getRepositoryClass (self, id):
- return self.repository_map[id]
-
-
Copied: clippy/loader.py (from rev 8, clippy/core.py)
===================================================================
--- clippy/loader.py (rev 0)
+++ clippy/loader.py 2010-01-07 23:35:31 UTC (rev 9)
@@ -0,0 +1,104 @@
+# -*-python-*-
+# vim: set ts=4 sw=4 expandtab:
+
+import os.path
+
+
+def registerRepository (id, klass):
+ Loader.registerRepository (id, klass)
+
+
+class Loader (object):
+
+ repository_list = []
+ repository_map = {}
+
+
+ def __init__ (self):
+ pass
+
+ def loadRepositories (self, repo_dir):
+ import clippy.repositories
+ self.importRepositoryClasses (os.path.dirname (clippy.repositories.__file__))
+ #self.importRepositoryClasses (self.USER_REPO_DIR)
+ try:
+ self.loadRepositoryDefinitions (repo_dir, None)
+ except:
+ print "Skipping ", repo_dir
+ pass
+
+ def importRepositoryClasses (self, dir):
+ for file in sorted (os.listdir (dir)):
+ file, ext = os.path.splitext (file)
+ if not ext.lower () in ['.py', '.pyc', '.pyo', '.pyw']:
+ continue
+
+ # FIXME: or use execfile()?
+ exec 'import clippy.repositories.' + file
+
+
+ def loadRepositoryDefinitions (self, dir, progress_fn):
+ for file in sorted (os.listdir (dir)):
+ if not file.endswith ('.cfg'):
+ continue
+
+ # FIXME: this prevents developer to supply their
+ # own config class. Rather pass config class factory as an argument to this function
+ config = config.Config ()
+ config.read (os.path.join (dir, file))
+ config = config.config # FIXME: ugly
+
+ id = config['id']
+ # FIXME: check that id is unique?
+ klass = config['class']
+ klass = self.getRepositoryClass (klass)
+
+ # NOTE: the effect is that config keys defined in main config file
+ # shadow those in a repo definition file and in a class.
+ #for key, value in config.items ():
+ # if key == 'id' or key == 'class':
+ # continue
+ #
+ # key = 'repo.' + id + '.' + key
+ # if not key in self.config:
+ # #self.config[key] = value
+ # pass
+
+ self.registerRepository (id, klass, config)
+ #yield True
+ #yield False
+
+
+ @staticmethod
+ def registerRepository (id, klass, config = None):
+ # This method is called from repository modules
+
+ # get repo's config params.
+ # merge forward duplicate config keys, i.e. (name, dir, name) becomes (name, dir) (FIXME: just merge?)
+ # add config params to global config if they are not there yet
+ # create instance and give it id and some ref to config
+ # repo's __init__() sets attrs based on repo.<id>.xxxx
+
+ params = klass.getConfigParams ()
+ if config is None:
+ config = {}
+ for param in reversed (params):
+ key = param[0]
+ if not config.has_key (key):
+ config[key] = param[4]
+
+ Loader.repository_map[id] = (klass, config)
+
+ def getRepositories (self):
+ return self.repository_map
+
+ def getRepository (self, id):
+ klass, config = self.getRepositoryClass (id)
+ repo = klass (id, config.copy ())
+ return repo
+
+
+ def getRepositoryClass (self, id):
+ return self.repository_map[id]
+
+
Added: clippy/repositories/art_gnome_org_repo.py
===================================================================
--- clippy/repositories/art_gnome_org_repo.py (rev 0)
+++ clippy/repositories/art_gnome_org_repo.py 2010-01-07 23:35:31 UTC (rev 9)
@@ -0,0 +1,184 @@
+# -*-python-*-
+# vim: set ts=4 sw=4 expandtab:
+
+import mimetypes
+import os
+import os.path
+import re
+import urllib2
+
+from clippy import loader, repository, query
+from clippy.repository import *
+
+
+class ArtGnomeOrgRepository (repository.Repository):
+ def __init__ (self, id, config):
+ repository.Repository.__init__ (self, id, config)
+ self.base_url = 'http://art.gnome.org/backgrounds'
+ #self.search_url = self.base_url + '/tags'
+
+ #self.link_re = re.compile ('<a href="(' + self.base_url + '/files/([^/]+)/([0-9]+))">([^<]+)</a>')
+
+ #self.dload_re = re.compile ('<p><a href="(' + self.base_url + '/download/[^/]+/([0-9]+))" id="cc_downloadbutton" type="([^"]+)" title="([^"]+)"><span>([^<]*)</span></a>')
+ self.name_re = re.compile ('^<b>([^<>]+)</b>$')
+ self.author_re = re.compile ('^<span class="item-detail">by <script type=.*;</script>([^<>]*)<script type=\'text/javascript\'>document.write')
+ self.license_re = re.compile ('^<br><span class="item-detail"><a href="([^<>"]+)">([^<>]+)</a></span>$')
+ self.preview_re = re.compile ('^<img width="\\d+" height="\\d+" alt="Preview" src=\'(/images/thumbnails/.*)\'>$')
+ self.link_re = re.compile ('^<option value="(/[^<>"]+/(\\d+)/([^<>"/]+))">$')
+ self.type_re = re.compile ('^(\\d+x\\d+|scalable)\\s*</option>$')
+
+ @staticmethod
+ def getCaps ():
+ return REPO_REMOTE | REPO_GET | REPO_HAS_PAGES
+
+ @staticmethod
+ def getConfigParams ():
+ res = repository.Repository.getConfigParams ()
+ res.extend ([
+ ('name', 'Name', 'STR', 'Name...', 'art.Gnome.org (AGO) repository'),
+ ])
+ return res
+
+ def getQueryParams (self):
+ return [
+ #('tag', 'Tag', 'TAG', 'tag desc...', 'backgrounds'),
+ ('page', 'Page', 'NUM', 'page desc...', 0),
+ ]
+
+ def connect (self):
+# username = config['username']
+# password = config['password']
+#
+# auth_handler = urllib2.HTTPBasicAuthHandler ()
+# auth_handler.add_password (
+# realm = self.auth_realm,
+# uri = self.auth_uri,
+# user = username,
+# passwd = password)
+# # ...and install it globally so it can be used with urlopen.
+# opener = urllib2.build_opener (auth_handler)
+# urllib2.install_opener (opener)
+ self.tags = self.getTags ()
+
+ def disconnect (self):
+ self.tags = None
+
+
+ def getTags (self):
+ res = []
+ return res
+ f = urllib2.urlopen (self.search_url)
+ for line in f:
+ if line.find ('class="cc_tag_link"') >= 0:
+ pos = line.index ('>')
+ pos2 = line.index ('<', pos)
+ tag = line[pos+1:pos2]
+ res.append (tag)
+
+ return res
+
+
+ def getItems (self, query):
+ res = []
+
+ url = self.base_url
+ if query.page > 1:
+ url += '?page=' + query.page
+
+ f = urllib2.urlopen (url)
+ line = f.readline ()
+ while line:
+ line = line.strip ()
+
+ if not line.startswith ('<div class="list-item">'):
+ line = f.readline ()
+ continue
+
+ line = f.readline ().strip ()
+ mo = self.name_re.search (line)
+ if not mo:
+ print 'Line does not match line_re:', line
+ continue
+ name = mo.group (1)
+
+ f.readline ()
+
+ line = f.readline ().strip ()
+ mo = self.author_re.search (line)
+ if not mo:
+ print 'Line does not match author_re:', line
+ continue
+ author = mo.group (1)
+
+ line = f.readline ().strip ()
+ mo = self.license_re.search (line)
+ if not mo:
+ print 'Line does not match license_re:', line
+ continue
+ license_url = mo.group (1)
+ license = mo.group (2)
+
+ f.readline ()
+ line = f.readline ().strip ()
+
+ mo = self.preview_re.search (line)
+ if not mo:
+ print 'Line does not match preview_re:', line
+ continue
+
+ preview = mo.group (1)
+
+ f.readline ()
+ f.readline ()
+ f.readline ()
+ f.readline ()
+ f.readline ()
+ f.readline ()
+ line = f.readline ().strip ()
+
+ while line != '</select>':
+ mo = self.link_re.search (line)
+ if not mo:
+ print 'Line does not match link_re:', line
+ break
+
+ url = 'http://art.gnome.org/download?d=' + mo.group (1)
+ id = mo.group (2)
+ filename = mo.group (3)
+
+ line = f.readline ().strip ()
+
+ mo = self.type_re.search (line)
+ if not mo:
+ print 'Line does not match type_re:', line
+ break
+
+ type = mo.group (1)
+
+ meta = {
+ 'id': id,
+ 'name': name,
+ 'filename': filename,
+ 'author': author,
+ 'license': license,
+ 'license_url': license_url,
+ 'type': type,
+ 'preview': 'http://art.gnome.org' + preview,
+ 'url': url,
+ }
+ res.append (meta)
+ line = f.readline ().strip ()
+
+
+ f.close ()
+ return res
+
+
+ def getData (self, metadata):
+ f = urllib2.urlopen (metadata['url'])
+
+ data = f.read ()
+ return data
+
+
+loader.registerRepository ('art_gnome_org_repo', ArtGnomeOrgRepository)
Modified: clippy/repositories/dia_shapes_repo.py
===================================================================
--- clippy/repositories/dia_shapes_repo.py 2010-01-01 21:14:58 UTC (rev 8)
+++ clippy/repositories/dia_shapes_repo.py 2010-01-07 23:35:31 UTC (rev 9)
@@ -8,7 +8,7 @@
import urllib2
from xml.dom.minidom import parse, parseString
-from clippy import core, repository
+from clippy import loader, repository
class DiaShapesRepository (repository.Repository):
@@ -66,4 +66,4 @@
return data
-core.registerRepository ('dia_shapes_repo', DiaShapesRepository)
+loader.registerRepository ('dia_shapes_repo', DiaShapesRepository)
Modified: clippy/repositories/ghns_repo.py
===================================================================
--- clippy/repositories/ghns_repo.py 2010-01-01 21:14:58 UTC (rev 8)
+++ clippy/repositories/ghns_repo.py 2010-01-07 23:35:31 UTC (rev 9)
@@ -7,7 +7,7 @@
import urllib2
from xml.dom.minidom import parse, parseString
-from clippy import core, repository
+from clippy import loader, repository
class GHNSRepository (repository.Repository):
@@ -116,4 +116,4 @@
return data
-core.registerRepository ('ghns_repo', GHNSRepository)
+loader.registerRepository ('ghns_repo', GHNSRepository)
Modified: clippy/repositories/local_dir_repo.py
===================================================================
--- clippy/repositories/local_dir_repo.py 2010-01-01 21:14:58 UTC (rev 8)
+++ clippy/repositories/local_dir_repo.py 2010-01-07 23:35:31 UTC (rev 9)
@@ -7,7 +7,7 @@
import stat
import string
-from clippy import core, repository
+from clippy import loader, repository
from clippy.repository import *
@@ -85,4 +85,4 @@
fh.close ()
-core.registerRepository ('local_dir_repo', LocalDirRepository)
+loader.registerRepository ('local_dir_repo', LocalDirRepository)
Modified: clippy/repositories/ocal_repo.py
===================================================================
--- clippy/repositories/ocal_repo.py 2010-01-01 21:14:58 UTC (rev 8)
+++ clippy/repositories/ocal_repo.py 2010-01-07 23:35:31 UTC (rev 9)
@@ -6,7 +6,7 @@
import re
import urllib2
-from clippy import core, repository, query
+from clippy import loader, repository, query
from clippy.repository import *
@@ -111,4 +111,4 @@
return data
-core.registerRepository ('ocal_repo', OCALRepository)
+loader.registerRepository ('ocal_repo', OCALRepository)
Modified: clippy/repositories/rest_repo.py
===================================================================
--- clippy/repositories/rest_repo.py 2010-01-01 21:14:58 UTC (rev 8)
+++ clippy/repositories/rest_repo.py 2010-01-07 23:35:31 UTC (rev 9)
@@ -5,7 +5,7 @@
import urllib2
from xml.dom.minidom import parse, parseString
-from clippy import core, repository
+from clippy import loader, repository
from clippy.repository import *
@@ -92,4 +92,4 @@
return data
-core.registerRepository ('rest_repo', RestRepository)
+loader.registerRepository ('rest_repo', RestRepository)
Modified: clippy/repository.py
===================================================================
--- clippy/repository.py 2010-01-01 21:14:58 UTC (rev 8)
+++ clippy/repository.py 2010-01-07 23:35:31 UTC (rev 9)
@@ -1,6 +1,5 @@
# -*-python-*-
# vim: set ts=4 sw=4 expandtab:
-from clippy import core
REPO_LOCAL = 0
REPO_CACHE = 0
@@ -23,7 +22,6 @@
class Repository (object):
def __init__ (self, id, config):
- self.core = core.clippy_core
self.id = id
self.config = config
self.name = self.getConfig ('name')
Modified: clippy/ui/__init__.py
===================================================================
--- clippy/ui/__init__.py 2010-01-01 21:14:58 UTC (rev 8)
+++ clippy/ui/__init__.py 2010-01-07 23:35:31 UTC (rev 9)
@@ -1,4 +1,5 @@
# -*-python-*-
-from assistant.ui import ClippyAssistant
+#from shell.ui import ClippyShell
+#from assistant.ui import ClippyAssistant
#from commander.app import ClippyCommander
Modified: clippy/ui/assistant/app.py
===================================================================
--- clippy/ui/assistant/app.py 2010-01-01 21:14:58 UTC (rev 8)
+++ clippy/ui/assistant/app.py 2010-01-07 23:35:31 UTC (rev 9)
@@ -1,22 +1,93 @@
#!/usr/bin/env python
+# vim: set ts=4 sw=4 expandtab:
from optparse import OptionParser
-from clippy.ui import ClippyAssistant
+import os
+import os.path
+import re
-oparser = OptionParser ()
-oparser.add_option ("-s",
+import gtk
+import gtk.glade
+
+from clippy import loader, utils
+from clippy.ui import glfactory
+from clippy.ui.assistant import win_main
+from clippy.ui.assistant import win_repo_config
+
+#################################################
+app = None
+
+#################################################
+#################################################
+
+class ClippyAssistant:
+ column_hash = {
+ 'name': ( 'Name', 'str'),
+ 'id': ( 'ID', 'str'),
+ 'desc': ( 'Desc', 'str'),
+ 'type': ( 'Type', 'str'),
+ 'filename': ( 'Filename', 'str'),
+ 'selection': ('S', 'bool'),
+ }
+
+ COL_HEADER = 0
+ COL_TYPE = 1
+
+ def __init__ (self):
+ global app
+
+ app = self
+ win_main.app = self
+
+ self.repo_source = None
+ self.repo_target = None
+
+ self.skip_targets = False
+ self.skip_sources = False
+ self.skip_confirm = False
+ # FIXME: option for swapping order of source and target pages
+
+ self.item_list_mode = 'both' # one of: src, tgt, both
+
+ self.icon_dir = '.'
+ self.icons = {}
+
+ self.columns = [ 'name', 'desc' ]
+ self.columns_item = { '': [ 'name', 'id', 'type', 'selection', 'filename' ] }
+
+ # Map w/ references to already created windows
+ self.windows = {}
+ self.win_main = None
+ #win_main.app = app
+
+ # FIXME: maybe cli args and config should be called first
+ #print "Init Core"
+ self.loader = loader.Loader ()
+ self.loader.loadRepositories (utils.USER_REPO_DIR)
+
+ # Load Prepare UI for launch
+ ###self.setup ()
+
+ def main (self):
+ self.parse_args ()
+ self.setup ()
+ self.run ()
+
+ def parse_args (self):
+ oparser = OptionParser ()
+ oparser.add_option ("-s",
"--source",
dest = "source",
help = "use source repository REPOID and skip source selection page",
metavar = "REPOID")
-oparser.add_option ("-t",
+ oparser.add_option ("-t",
"--target",
dest = "target",
help = "use target repository REPOID and skip target selection page",
metavar = "REPOID")
-oparser.add_option ("-i",
+ oparser.add_option ("-i",
"--item-list-mode",
dest = "item_list_mode",
help = "item list mode MODE",
@@ -24,28 +95,199 @@
metavar = "MODE")
-oparser.add_option ("-y",
+ oparser.add_option ("-y",
"--skip-confirm",
dest = "skip_confirm",
action = "store_true",
default = False,
help = "skip download confirmation page")
-(opts, args) = oparser.parse_args ()
+ (opts, args) = oparser.parse_args ()
-app = ClippyAssistant ()
-if opts.target is not None:
- r = app.core.getRepository (opts.target)
- app.setTargetRepository (r)
+ if opts.target is not None:
+ r = self.loader.getRepository (opts.target)
+ self.setTargetRepository (r)
-if opts.source is not None:
- r = app.core.getRepository (opts.source)
- app.setSourceRepository (r)
+ if opts.source is not None:
+ r = self.loader.getRepository (opts.source)
+ self.setSourceRepository (r)
-if opts.item_list_mode is not None:
- app.item_list_mode = opts.item_list_mode
+ if opts.item_list_mode is not None:
+ self.item_list_mode = opts.item_list_mode
-app.skip_confirm = opts.skip_confirm
+ self.skip_confirm = opts.skip_confirm
-app.run ()
+
+ def setup (self):
+ self.glade_file = os.path.expanduser (self.getConfig ('ui.glade_file'))
+
+
+ #print "Loading UI"
+ self.wtree = gtk.glade.XML (self.glade_file)
+ self.factory = myFactory (self.wtree)
+
+ #self.icons['XXXX'] = gtk.gdk.pixbuf_new_from_file (os.path.join (app.icon_dir, 'xxxx.png'))
+ self.win_main = self.factory ("win_main")
+ #self.win_main.setup ()
+ self.win_main.show ()
+
+
+ def run (self):
+ gtk.main ()
+
+ def restore_geometry (self, window, window_name):
+ geometry = self.getConfig ('ui.%s.geometry' %window_name)
+ mo = re.match (r'(\d+)x(\d+)([+-]\d+)([+-]\d+)', geometry)
+ if mo is not None:
+ geometry = map (int, mo.group (3, 4, 1, 2))
+ window.resize (geometry[2], geometry[3])
+ window.move (geometry[0], geometry[1])
+
+ def save_geometry (self, window, window_name):
+ x, y = window.get_position ()
+ w, h = window.get_size ()
+ geometry = "%dx%d+%d+%d" %(w, h, x, y)
+ self.setConfig ('ui.%s.geometry'%window_name, geometry)
+ # FIXME: account for fullscreen
+
+ def progress_fn (self, msg, percent):
+ #self.splash_window.update_progress (msg, percent)
+ pass
+
+
+ def setSourceRepository (self, repo):
+ self.repo_source = repo
+ self.skip_sources = True
+
+
+ def setTargetRepository (self, repo):
+ self.repo_target = repo
+ self.skip_targets = True
+
+
+ # NOTE: this method should be overridden in a child class
+ def getConfig (self, key):
+ # FIXME: should be in default config?
+ cfg = {
+ 'ui.glade_file': os.path.join (os.path.dirname (__file__) , 'ui.glade'), # NOTE: glade file has to be with python files, not in /usr/share
+ 'ui.win_main.geometry': '500x350+30+30',
+ }
+
+ return cfg[key]
+
+ def setConfig (self, key, value):
+ pass
+
+# def open_url (self, url):
+# if app.browser.find ('%s') >= 0:
+# os.system (app.browser %url)
+# else:
+# os.system (app.browser + " '" + url + "'")
+#
+#
+# def help (self, topic):
+# self.open_url (app.help_url + '/' + topic + '.html')
+#
+
+# def run_dialog (self, win_name, update_args = (), closers = ()):
+# try: win = self.windows[win_name]
+# except: win = self.windows[win_name] = self.factory (win_name)
+#
+# if callable (update_args):
+# update_args (win)
+# else:
+# try:
+# apply (win.update, update_args)
+# except AttributeError:
+# print "Warning: %s has no update() fn" %win_name
+#
+# while True:
+# res = win.run ()
+# if res in (gtk.RESPONSE_OK, gtk.RESPONSE_CLOSE, gtk.RESPONSE_CANCEL, gtk.RESPONSE_DELETE_EVENT) + closers:
+# # FIXME: maybe it would be better to let the caller do win.hide ()
+# win.hide ()
+# return res, win
+#
+# if res == gtk.RESPONSE_HELP:
+# self.help (win_name)
+
+
+#################################################
+#class win_save (glfactory.glObject):
+# def init_widget (self):
+# model = gtk.ListStore (int, str, str)
+# self['treesaveformats'].set_model (model)
+#
+# for fmt in app.formats:
+# model.append (i, fmt[0], fmt[1])
+#
+# renderer = gtk.CellRendererText ()
+#
+# column = gtk.TreeViewColumn ('ext', renderer, text = 1)
+# self['treesaveformats'].append_column (column)
+#
+# column = gtk.TreeViewColumn ('Name', renderer, text = 2)
+# self['treesaveformats'].append_column (column)
+#
+# def on_destroy (self, widget):
+# gtk.main_quit ()
+
+
+#################################################
+class win_metadata (glfactory.glObject):
+ def init_widget (self):
+ self.model = gtk.ListStore (str, str)
+ tree = self['tree_metadata']
+ tree.set_model (self.model)
+
+ text_renderer = gtk.CellRendererText ()
+
+ column = gtk.TreeViewColumn ("Key", text_renderer, text = 0)
+ tree.append_column (column)
+
+ column = gtk.TreeViewColumn ("Value", text_renderer, text = 1)
+ tree.append_column (column)
+ self.restore_geometry (self, 'win_metadata')
+
+
+ def update (self, meta):
+ self.model.clear ()
+ for key in sorted (meta.keys ()):
+ self.model.append ([key, str (meta[key])])
+
+ def on_but_metadata_close_clicked (self, *args):
+ self.hide ()
+
+ def on_delete_event (self, *args):
+ self.hide ()
+ return 1
+
+
+#################################################
+class win_about (glfactory.glObject):
+ def update (self):
+ pass
+
+
+#################################################
+class myFactory (glfactory.glFactory):
+ classes = {
+ 'win_main': win_main.win_main,
+ 'win_metadata': win_metadata,
+ 'win_repo_config': win_repo_config.win_repo_config,
+ 'win_repo_query': win_repo_config.win_repo_query,
+ #'win_about': win_about,
+ }
+
+
+#################################################
+if __name__ == '__main__':
+ # FIXME: need to setup import root to ../..
+ app = ClippyAssistant ()
+ app.main ()
+
+
+#################################################
+# End of file app.py
+
Modified: clippy/ui/assistant/ui.py
===================================================================
--- clippy/ui/assistant/ui.py 2010-01-01 21:14:58 UTC (rev 8)
+++ clippy/ui/assistant/ui.py 2010-01-07 23:35:31 UTC (rev 9)
@@ -9,7 +9,7 @@
import gtk
import gtk.glade
-from clippy import core, utils
+from clippy import loader, utils
from clippy.ui import glfactory
from clippy.ui.assistant import win_main
from clippy.ui.assistant import win_repo_config
@@ -36,8 +36,8 @@
def __init__ (self):
global ui
- ui = self
- win_main.ui = self
+ app = self
+ win_main.app = self
self.repo_source = None
self.repo_target = None
@@ -61,8 +61,8 @@
#win_main.app = app
#print "Init Core"
- self.core = core.Loader ()
- self.core.loadRepositories (utils.USER_REPO_DIR)
+ self.loader = loader.Loader ()
+ self.loader.loadRepositories (utils.USER_REPO_DIR)
# Load Prepare UI for launch
self.setup ()
Modified: clippy/ui/assistant/win_main.py
===================================================================
--- clippy/ui/assistant/win_main.py 2010-01-01 21:14:58 UTC (rev 8)
+++ clippy/ui/assistant/win_main.py 2010-01-07 23:35:31 UTC (rev 9)
@@ -7,13 +7,13 @@
import pango
import string
-from clippy import core, repository
+from clippy import loader, repository, utils
from clippy.query import Query
from clippy.ui import glfactory
#################################################
-ui = None
+app = None
name_lookup = ''
@@ -51,7 +51,7 @@
return ".."
if col == 'selection':
- if ui.win_main.selection.has_key (id (obj)):
+ if app.win_main.selection.has_key (id (obj)):
return True
else:
return False
@@ -71,8 +71,8 @@
if not obj:
return False # FIXME: why do the null objects occur at all????
- if ui.filter:
- for f in ui.filter:
+ if app.filter:
+ for f in app.filter:
if not f (obj): return False
@@ -119,7 +119,7 @@
'on_menu_repo_query_activate': self.handle_open_repo_query,
'on_menu_item_metadata_activate': self.handle_open_metadata,
}
- ui.wtree.signal_autoconnect (signal_dict)
+ app.wtree.signal_autoconnect (signal_dict)
self.set_forward_page_func (self.forward_fn)
self.set_page_complete (self.get_nth_page (self.PAGE_INTRO), True)
@@ -158,7 +158,7 @@
# FIXME: should not be here
self.selection = {}
- ui.restore_geometry (self, 'win_main')
+ app.restore_geometry (self, 'win_main')
def setup_list (self, page):
@@ -166,17 +166,17 @@
coltypes = []
if page == self.PAGE_SOURCES:
- columns += ui.columns
+ columns += app.columns
self.model_sources = model = gtk.ListStore (object)
self.model_sources_filtered = filtered = model.filter_new ()
tree = self['tree_sources']
elif page == self.PAGE_TARGETS:
- columns += ui.columns
+ columns += app.columns
self.model_targets = model = gtk.ListStore (object)
self.model_targets_filtered = filtered = model.filter_new ()
tree = self['tree_targets']
else: # items
- columns += ui.columns_item['']
+ columns += app.columns_item['']
self.model_items = model = gtk.ListStore (object)
self.model_items_filtered = filtered = model.filter_new ()
tree = self['tree_items']
@@ -187,8 +187,8 @@
coltypes.append (object)
continue
- desc = ui.column_hash[c]
- col_type = desc[ui.COL_TYPE]
+ desc = app.column_hash[c]
+ col_type = desc[app.COL_TYPE]
if col_type == 'img':
coltypes.append (gtk.gdk.Pixbuf)
elif col_type == 'bool':
@@ -233,9 +233,9 @@
i = 1
for c in columns[1:]:
- desc = ui.column_hash[c]
- col_label = desc[ui.COL_HEADER]
- col_type = desc[ui.COL_TYPE]
+ desc = app.column_hash[c]
+ col_label = desc[app.COL_HEADER]
+ col_type = desc[app.COL_TYPE]
if col_type == 'img':
column = gtk.TreeViewColumn (col_label, img_renderer, pixbuf = i)
elif col_type == 'bool':
@@ -267,8 +267,8 @@
# FIXME: should also disable sorting
model.clear ()
- for id in ui.core.getRepositories ():
- klass, config = ui.core.getRepositoryClass (id)
+ for id in app.loader.getRepositories ():
+ klass, config = app.loader.getRepositoryClass (id)
if klass.getCaps () & caps_mask:
repo = klass (id, config)
else:
@@ -295,7 +295,7 @@
# FIXME: some list modes do not need source or target items, so do not load them
try:
- repo = ui.repo_target
+ repo = app.repo_target
qry = Query (repo)
repo.connect ()
items_tgt = repo.getItems (qry)
@@ -305,7 +305,7 @@
print "Can't get target items:", e
try:
- repo = ui.repo_source
+ repo = app.repo_source
qry = Query (repo)
repo.connect ()
items_src = repo.getItems (qry)
@@ -316,13 +316,13 @@
# FIXME: this part should be in core
- if ui.item_list_mode in ['both', 'tgt', 'merge']:
+ if app.item_list_mode in ['both', 'tgt', 'merge']:
items.extend (items_tgt)
- if ui.item_list_mode in ['both', 'src', 'merge']:
+ if app.item_list_mode in ['both', 'src', 'merge']:
items.extend (items_src)
- if ui.item_list_mode in ['merge']:
+ if app.item_list_mode in ['merge']:
item_hash = {}
for item in items:
if item_hash.has_key (item['name']):
@@ -334,7 +334,7 @@
items = item_hash.values ()
- if ui.item_list_mode in ['new']:
+ if app.item_list_mode in ['new']:
item_hash = {}
for item in items_tgt:
item_hash[item['name']] = item
@@ -343,7 +343,7 @@
if not item_hash.has_key (item['name']):
items.append (item)
- print "MODE", ui.item_list_mode
+ print "MODE", app.item_list_mode
items = sorted (items, None, lambda item: item['name'])
#self.model_items.append (None)
for item in items:
@@ -355,10 +355,10 @@
def handle_open_metadata (self, *args):
try:
- win = ui.windows['win_metadata']
+ win = app.windows['win_metadata']
except:
- win = ui.factory ('win_metadata')
- ui.windows['win_metadata'] = win
+ win = app.factory ('win_metadata')
+ app.windows['win_metadata'] = win
if self.get_current_page () == self.PAGE_ITEMS:
tree = self['tree_items']
@@ -374,15 +374,15 @@
def handle_open_repo_config (self, *args):
try:
- win = ui.windows['win_repo_config']
+ win = app.windows['win_repo_config']
except:
- win = ui.factory ('win_repo_config')
- ui.windows['win_repo_config'] = win
+ win = app.factory ('win_repo_config')
+ app.windows['win_repo_config'] = win
if self.get_current_page () == self.PAGE_SOURCES:
- repo = ui.repo_source
+ repo = app.repo_source
else:
- repo = ui.repo_target
+ repo = app.repo_target
win.update (repo)
win.show ()
@@ -390,23 +390,23 @@
def handle_open_repo_query (self, *args):
try:
- win = ui.windows['win_repo_query']
+ win = app.windows['win_repo_query']
except:
- win = ui.factory ('win_repo_query')
- ui.windows['win_repo_query'] = win
+ win = app.factory ('win_repo_query')
+ app.windows['win_repo_query'] = win
if self.get_current_page () == self.PAGE_SOURCES:
- repo = ui.repo_source
+ repo = app.repo_source
query = self.query_source
else:
- repo = ui.repo_target
+ repo = app.repo_target
query = self.query_target
win.update (repo, query)
win.show ()
def handle_preferences (self):
- res, win = ui.run_dialog ('win_preferences')
+ res, win = app.run_dialog ('win_preferences')
if res == gtk.RESPONSE_OK:
# FIXME: should we recompute cache.found for the new nickname???
self.update ()
@@ -414,20 +414,20 @@
## win.hide ()
def handle_open_url (self, url):
- if ui.browser.find ('%s') >= 0:
- os.system (ui.browser %url)
+ if app.browser.find ('%s') >= 0:
+ os.system (app.browser %url)
else:
- os.system (ui.browser + " '" + url + "'")
+ os.system (app.browser + " '" + url + "'")
def handle_open_help (self, topic):
- self.handle_open_url (ui.help_url + '/' + topic + '.html')
+ self.handle_open_url (app.help_url + '/' + topic + '.html')
def menu_preferences (self, *args):
self.handle_preferences ()
def menu_about (self, *args):
- res, win = ui.run_dialog ('win_about')
+ res, win = app.run_dialog ('win_about')
@@ -467,11 +467,11 @@
repo = model.get_value (iter, 0)
page = self.get_current_page ()
if page == self.PAGE_TARGETS:
- ui.repo_target = repo
- ui.repo_source = None # do new source repos filter
+ app.repo_target = repo
+ app.repo_source = None # do new source repos filter
self.set_page_complete (self.get_nth_page (self.PAGE_TARGETS), True)
elif page == self.PAGE_SOURCES:
- ui.repo_source = repo
+ app.repo_source = repo
self.selection = None
# FIXME: invalidate items
self.set_page_complete (self.get_nth_page (self.PAGE_SOURCES), True)
@@ -537,7 +537,7 @@
#if s != None:
# app.core.setConfig ('ui.split_position', str (s))
- ui.save_geometry (self, 'win_main')
+ app.save_geometry (self, 'win_main')
def on_tree_sources_button_press_event (self, widget, ev):
@@ -545,7 +545,7 @@
return
if ev.button == 3:
- popup = ui.wtree.get_widget ('menu_repo')
+ popup = app.wtree.get_widget ('menu_repo')
popup.popup (None, None, None, 0, 0)
#elif ev.type == gtk.gdk._2BUTTON_PRESS:
@@ -558,7 +558,7 @@
return
if ev.button == 3:
- popup = ui.wtree.get_widget ('menu_repo')
+ popup = app.wtree.get_widget ('menu_repo')
popup.popup (None, None, None, 0, 0)
#elif ev.type == gtk.gdk._2BUTTON_PRESS:
@@ -570,7 +570,7 @@
return
if ev.button == 3:
- popup = ui.wtree.get_widget ('menu_item')
+ popup = app.wtree.get_widget ('menu_item')
popup.popup (None, None, None, 0, 0)
#elif ev.type == gtk.gdk._2BUTTON_PRESS:
@@ -598,11 +598,11 @@
print "FWD", args
page = args[0]
next = page + 1
- if next == self.PAGE_TARGETS and ui.skip_targets:
+ if next == self.PAGE_TARGETS and app.skip_targets:
next = next + 1
- if next == self.PAGE_SOURCES and ui.skip_sources:
+ if next == self.PAGE_SOURCES and app.skip_sources:
next = next + 1
- if next == self.PAGE_CONFIRM and ui.skip_confirm:
+ if next == self.PAGE_CONFIRM and app.skip_confirm:
next = next + 1
return next
@@ -613,11 +613,11 @@
print "PREPARE" , page
if page == self.PAGE_TARGETS:
print "TARGETS"
- if ui.repo_target is None:
+ if app.repo_target is None:
self.update_repo_list (self.PAGE_TARGETS)
elif page == self.PAGE_SOURCES:
print "SOURCES"
- if ui.repo_source is None:
+ if app.repo_source is None:
self.update_repo_list (self.PAGE_SOURCES)
elif page == self.PAGE_ITEMS:
print "ITEMS"
@@ -633,11 +633,33 @@
print "PROGRESS"
self.log_buf.delete (self.log_buf.get_start_iter (), self.log_buf.get_end_iter ())
#self['vb_page_download'].show ()
- gtk.idle_add (ui.core.xfer (ui.repo_source, ui.repo_target, self.selection, self.progress_fn, self.log_fn).next)
+ gtk.idle_add (utils.xfer (app.repo_source, app.repo_target, self.selection, self.progress_fn).next)
#ui.core.xfer (ui.repo_source, ui.repo_target, self.selection, self.progress_fn, self.log_fn)
- def progress_fn (self, total, total_msg, file, file_msg):
+
+ def progress_fn (self, state, **kw):
+ if state == utils.XFER_START:
+ print "Starting transfer..."
+ elif state == utils.XFER_FILE_START:
+ self['progress_file'].set_fraction (0)
+ self['progress_file'].set_text (kw['name'])
+ self.log_buf.insert (self.log_buf.get_end_iter (), kw['name'] + ' ... ')
+ elif state == utils.XFER_FILE_UPDATE:
+ pass
+ elif state == utils.XFER_FILE_OK:
+ self['progress_file'].set_fraction (1.0)
+ self.log_buf.insert_with_tags_by_name (self.log_buf.get_end_iter (), "OK\n", "ok")
+ elif state == utils.XFER_FILE_ERROR:
+ self.log_buf.insert_with_tags_by_name (self.log_buf.get_end_iter (), "ERROR\n", "error")
+ elif state == utils.XFER_END:
+ print 'Transfer complete'
+ else:
+ pass
+
+ self['text_log'].scroll_to_mark (self.log_buf.get_insert (), 0.05, True, 0.0, 1.0)
+
+ def progressx_fn (self, total, total_msg, file, file_msg):
self['progress_file'].set_fraction (file)
self['progress_file'].set_text (file_msg)
self['progress_total'].set_fraction (total)
Modified: clippy/ui/shell/app.py
===================================================================
--- clippy/ui/shell/app.py 2010-01-01 21:14:58 UTC (rev 8)
+++ clippy/ui/shell/app.py 2010-01-07 23:35:31 UTC (rev 9)
@@ -4,9 +4,9 @@
import atexit
import os.path
import readline
+import sys
import traceback
-
-from clippy.core import Loader
+from clippy.loader import Loader
from clippy.query import Query
import clippy.utils as utils
@@ -14,11 +14,17 @@
HISTORY_FILE = os.path.join (utils.CONFIG_DIR, "cclippy.history")
def __init__ (self):
- self.core = Loader ()
- self.core.loadRepositories (utils.USER_REPO_DIR)
+ self.loader = Loader ()
+ self.loader.loadRepositories (utils.USER_REPO_DIR)
self._readline_init ()
self.encoding = 'ascii'
+ def quit (self):
+ try:
+ readline.write_history_file (self.HISTORY_FILE)
+ except IOError, e:
+ print >>sys.stderr, "W: Can't write history file `%s':" %self.HISTORY_FILE, e
+
def _readline_init (self):
"""Enable history and tab completion for the command line."""
@@ -29,7 +35,7 @@
except IOError:
pass
- atexit.register (readline.write_history_file, self.HISTORY_FILE)
+ atexit.register (self.quit)
###readline.set_pre_input_hook (self._readline_hook)
def _readline_hook ():
@@ -119,7 +125,11 @@
print "Source: ", source_name
print "Target: ", target_name
- cmd = raw_input ('Cmd: ')
+ try:
+ cmd = raw_input ('Cmd: ')
+ except EOFError:
+ print
+ cmd = 'q'
try:
cmd, arg = cmd.split (' ', 1)
@@ -137,21 +147,21 @@
elif cmd == 's' or cmd == 't':
if arg is None:
- for (i, id) in enumerate (sorted (self.core.getRepositories ())):
+ for (i, id) in enumerate (sorted (self.loader.getRepositories ())):
# FIXME: this is rather ugly
- klass, config = self.core.getRepositoryClass (id)
+ klass, config = self.loader.getRepositoryClass (id)
name = config['name']
desc = config['desc']
print '[%d]\t%s - %s\n\t\t%s' %(i, id, name, desc)
else:
try:
arg = int (arg)
- arg = sorted (self.core.getRepositories ())[arg]
+ arg = sorted (self.loader.getRepositories ())[arg]
except:
pass
#try:
- repo = self.core.getRepository (arg)
+ repo = self.loader.getRepository (arg)
#except Exception, e:
# print e
# continue
@@ -245,7 +255,9 @@
else:
print "Unknown command:", cmd
+ print "Quit..."
+
def main ():
app = Shell ()
app.run_shell ()
Modified: clippy/utils.py
===================================================================
--- clippy/utils.py 2010-01-01 21:14:58 UTC (rev 8)
+++ clippy/utils.py 2010-01-07 23:35:31 UTC (rev 9)
@@ -2,6 +2,7 @@
# vim: set ts=4 sw=4 expandtab:
import os.path
+import traceback
SYS_CONFIG_FILE = '/etc/clippy.cfg'
CONFIG_DIR = os.path.expanduser ('~/.clippy')
@@ -44,6 +45,7 @@
target.putData (obj, data)
except Exception, e:
progress_fn (XFER_FILE_ERROR, source=source, target=target, progress=progress, name=obj['name'], error=unicode (e))
+ traceback.print_exc ()
# FIXME: delete t,p file
yield True
continue
Modified: setup.py
===================================================================
--- setup.py 2010-01-01 21:14:58 UTC (rev 8)
+++ setup.py 2010-01-07 23:35:31 UTC (rev 9)
@@ -9,11 +9,13 @@
author = 'Jarda Benkovsky',
author_email = 'edh...@us...',
url = 'http://www.eowyn.cz/clippy',
- scripts = ['cclippy.py'],
- packages = ['clippy', 'clippy.repositories', 'clippy.ui.assistant', 'clippy.ui.commander'],
+ license = 'GPL',
+ scripts = ['cclippy', 'gclippy'],
+ #packages = ['clippy', 'clippy.repositories', 'clippy.ui.shell', 'clippy.ui.assistant', 'clippy.ui.commander'],
+ packages = ['clippy', 'clippy.repositories', 'clippy.ui.shell', 'clippy.ui.assistant'],
data_files = [('share/clippy/assistant', ['clippy/ui/assistant/ui.glade', 'logo.png', 'icon.png']),
('share/clippy/icons', glob.glob ('icons/*.png')),
- ('share/doc/clippy', ['TODO']),
- ('share/doc/gclippy/help', glob.glob ('help/*.html') + glob.glob ('help/*.css') + glob.glob ('help/*.png')),
+ ('share/doc/clippy', ['README', 'TODO']),
+ ('share/doc/clippy/help', glob.glob ('help/*.html') + glob.glob ('help/*.css') + glob.glob ('help/*.png')),
])
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|