properties.py :  » Installer » Zero-Install » zeroinstall-injector-0.47 » zeroinstall » 0launch-gui » Python Open Source

Home
Python Open Source
1.3.1.2 Python
2.Ajax
3.Aspect Oriented
4.Blog
5.Build
6.Business Application
7.Chart Report
8.Content Management Systems
9.Cryptographic
10.Database
11.Development
12.Editor
13.Email
14.ERP
15.Game 2D 3D
16.GIS
17.GUI
18.IDE
19.Installer
20.IRC
21.Issue Tracker
22.Language Interface
23.Log
24.Math
25.Media Sound Audio
26.Mobile
27.Network
28.Parser
29.PDF
30.Project Management
31.RSS
32.Search
33.Security
34.Template Engines
35.Test
36.UML
37.USB Serial
38.Web Frameworks
39.Web Server
40.Web Services
41.Web Unit
42.Wiki
43.Windows
44.XML
Python Open Source » Installer » Zero Install 
Zero Install » zeroinstall injector 0.47 » zeroinstall » 0launch gui » properties.py
# Copyright (C) 2009, Thomas Leonard
# See the README file for details, or visit http://0install.net.

import zeroinstall
from zeroinstall.support import tasks
from zeroinstall.injector.model import Interface,Feed,stable,testing,developer,stability_levels
from zeroinstall.injector.iface_cache import iface_cache
from zeroinstall.injector import writer,namespaces,gpg
from zeroinstall.gtkui import help_box

import gtk
from logging import warn

from dialog import DialogResponse,Template
from impl_list import ImplementationList
import time
import dialog
import compile

_dialogs = {}  # Interface -> Properties

def enumerate(items):
  x = 0
  for i in items:
    yield x, i
    x += 1

def format_para(para):
  lines = [l.strip() for l in para.split('\n')]
  return ' '.join(lines)

def have_source_for(policy, interface):
  # Note: we don't want to actually fetch the source interfaces at
  # this point, so we check whether:
  # - We have a feed of type 'src' (not fetched), or
  # - We have a source implementation in a regular feed
  have_src = False
  for f in interface.feeds:
    if f.machine == 'src':
      return True
  # Don't have any src feeds. Do we have a source implementation
  # as part of a regular feed?
  impls = interface.implementations.values()
  for f in policy.usable_feeds(interface):
    try:
      feed_iface = iface_cache.get_interface(f.uri)
      if feed_iface.implementations:
        impls.extend(feed_iface.implementations.values())
    except zeroinstall.NeedDownload:
      pass  # OK, will get called again later
    except Exception, ex:
      warn(_("Failed to load feed '%(feed)s': %(exception)s"), {'feed': f.uri, 'exception': str(ex)})
  for x in impls:
    if x.machine == 'src':
      return True
  return False

class Description:
  def __init__(self, widgets):
    description = widgets.get_widget('description')
    description.connect('button-press-event', self.button_press)

    self.buffer = description.get_buffer()
    self.heading_style = self.buffer.create_tag(underline = True, scale = 1.2)
    self.link_style = self.buffer.create_tag(underline = True, foreground = 'blue')
    description.set_size_request(-1, 100)
  
  def button_press(self, tv, bev):
    if bev.type == gtk.gdk.BUTTON_PRESS and bev.button == 1:
      x, y = tv.window_to_buffer_coords(tv.get_window_type(bev.window),
                int(bev.x), int(bev.y))
      itr = tv.get_iter_at_location(x, y)
      if itr and self.link_style in itr.get_tags():
        if not itr.begins_tag(self.link_style):
          itr.backward_to_tag_toggle(self.link_style)
        end = itr.copy()
        end.forward_to_tag_toggle(self.link_style)
        target = itr.get_text(end).strip()
        import browser
        browser.open_in_browser(target)
  
  def strtime(self, secs):
    try:
      from locale import nl_langinfo,D_T_FMT
      return time.strftime(nl_langinfo(D_T_FMT), time.localtime(secs))
    except ImportError, ValueError:
      return time.ctime(secs)

  def set_details(self, interface):
    buffer = self.buffer
    heading_style = self.heading_style

    buffer.delete(buffer.get_start_iter(), buffer.get_end_iter())

    iter = buffer.get_start_iter()

    buffer.insert_with_tags(iter,
      '%s ' % interface.get_name(), heading_style)
    buffer.insert(iter, '(%s)' % interface.summary)

    buffer.insert(iter, '\n%s\n' % interface.uri)

    # (converts to local time)
    if interface.last_modified:
      buffer.insert(iter, '\n' + _('Last upstream change: %s') % self.strtime(interface.last_modified))

    if interface.last_checked:
      buffer.insert(iter, '\n' + _('Last checked: %s') % self.strtime(interface.last_checked))

    last_check_attempt = iface_cache.get_last_check_attempt(interface.uri)
    if last_check_attempt:
      if interface.last_checked and interface.last_checked >= last_check_attempt:
        pass  # Don't bother reporting successful attempts
      else:
        buffer.insert(iter, '\n' + _('Last check attempt: %s (failed or in progress)') %
            self.strtime(last_check_attempt))

    buffer.insert_with_tags(iter, '\n\n' + _('Description') + '\n', heading_style)

    paragraphs = [format_para(p) for p in (interface.description or "-").split('\n\n')]

    buffer.insert(iter, '\n\n'.join(paragraphs))
    buffer.insert(iter, '\n')

    need_gap = True
    for x in interface.get_metadata(namespaces.XMLNS_IFACE, 'homepage'):
      if need_gap:
        buffer.insert(iter, '\n')
        need_gap = False
      buffer.insert(iter, _('Homepage: '))
      buffer.insert_with_tags(iter, '%s\n' % x.content, self.link_style)

    buffer.insert_with_tags(iter, '\n' + _('Signatures') + '\n', heading_style)
    sigs = iface_cache.get_cached_signatures(interface.uri)
    if sigs:
      for sig in sigs:
        if isinstance(sig, gpg.ValidSig):
          name = _('<unknown>')
          details = sig.get_details()
          for item in details:
            if item[0] == 'uid' and len(item) > 9:
              name = item[9]
              break
          buffer.insert_with_tags(iter, _('Valid signature by "%(name)s"\n- Dated: %(sig_date)s\n- Fingerprint: %(sig_fingerprint)s\n') %
              {'name': name, 'sig_date': time.strftime('%c', time.localtime(sig.get_timestamp())), 'sig_fingerprint': sig.fingerprint})
          if not sig.is_trusted():
            if interface.uri.startswith('/'):
              buffer.insert_with_tags(iter, _('WARNING: This key is not in the trusted list') + '\n')
            else:
              buffer.insert_with_tags(iter, _('WARNING: This key is not in the trusted list (either you removed it, or '
                      'you trust one of the other signatures)') + '\n')
        else:
          buffer.insert_with_tags(iter, '%s\n' % sig)
    else:
      buffer.insert_with_tags(iter, _('No signature information (old style interface or out-of-date cache)') + '\n')

class Feeds:
  URI = 0
  ARCH = 1
  USED = 2

  def __init__(self, policy, interface, widgets):
    self.policy = policy
    self.interface = interface

    self.model = gtk.ListStore(str, str, bool)

    self.description = Description(widgets)

    self.lines = self.build_model()
    for line in self.lines:
      self.model.append(line)

    add_remote_feed_button = widgets.get_widget('add_remote_feed')
    add_remote_feed_button.connect('clicked', lambda b: add_remote_feed(policy, widgets.get_widget(), interface))

    add_local_feed_button = widgets.get_widget('add_local_feed')
    add_local_feed_button.connect('clicked', lambda b: add_local_feed(policy, interface))

    self.remove_feed_button = widgets.get_widget('remove_feed')
    def remove_feed(button):
      model, iter = self.tv.get_selection().get_selected()
      feed_uri = model[iter][Feeds.URI]
      for x in interface.feeds:
        if x.uri == feed_uri:
          if x.user_override:
            interface.extra_feeds.remove(x)
            writer.save_interface(interface)
            policy.recalculate()
            return
          else:
            dialog.alert(self.get_toplevel(),
              _("Can't remove '%s' as you didn't add it.") % feed_uri)
            return
      raise Exception(_("Missing feed '%s'!") % feed_uri)
    self.remove_feed_button.connect('clicked', remove_feed)

    self.tv = widgets.get_widget('feeds_list')
    self.tv.set_model(self.model)
    text = gtk.CellRendererText()
    self.tv.append_column(gtk.TreeViewColumn(_('Source'), text, text = Feeds.URI, sensitive = Feeds.USED))
    self.tv.append_column(gtk.TreeViewColumn(_('Arch'), text, text = Feeds.ARCH, sensitive = Feeds.USED))

    sel = self.tv.get_selection()
    sel.set_mode(gtk.SELECTION_BROWSE)
    sel.connect('changed', self.sel_changed)
    sel.select_path((0,))
  
  def build_model(self):
    usable_feeds = frozenset(self.policy.usable_feeds(self.interface))
    unusable_feeds = frozenset(self.interface.feeds) - usable_feeds

    out = [[self.interface.uri, None, True]]

    if self.interface.feeds:
      for feed in usable_feeds:
        out.append([feed.uri, feed.arch, True])
      for feed in unusable_feeds:
        out.append([feed.uri, feed.arch, False])
    return out

  def sel_changed(self, sel):
    model, miter = sel.get_selected()
    if not miter: return  # build in progress
    iface = model[miter][Feeds.URI]
    # Only enable removing user_override feeds
    enable_remove = False
    for x in self.interface.feeds:
      if x.uri == iface:
        if x.user_override:
          enable_remove = True
    self.remove_feed_button.set_sensitive( enable_remove )
    self.description.set_details(iface_cache.get_interface(iface))
  
  def updated(self):
    new_lines = self.build_model()
    if new_lines != self.lines:
      self.lines = new_lines
      self.model.clear()
      for line in self.lines:
        self.model.append(line)
      self.tv.get_selection().select_path((0,))
    else:
      self.sel_changed(self.tv.get_selection())

class Properties:
  interface = None
  use_list = None
  window = None
  policy = None

  def __init__(self, policy, interface, show_versions = False):
    self.policy = policy

    widgets = Template('interface_properties')

    self.interface = interface

    window = widgets.get_widget('interface_properties')
    self.window = window
    window.set_title(_('Properties for %s') % interface.get_name())
    window.set_default_size(-1, gtk.gdk.screen_height() / 3)

    self.compile_button = widgets.get_widget('compile')
    self.compile_button.connect('clicked', lambda b: compile.compile(policy, interface))
    window.set_default_response(gtk.RESPONSE_CANCEL)

    def response(dialog, resp):
      if resp == gtk.RESPONSE_CANCEL:
        window.destroy()
      elif resp == gtk.RESPONSE_HELP:
        properties_help.display()
    window.connect('response', response)

    notebook = widgets.get_widget('interface_notebook')
    assert notebook

    feeds = Feeds(policy, interface, widgets)

    stability = widgets.get_widget('preferred_stability')
    stability.set_active(0)
    if interface.stability_policy:
      i = [stable, testing, developer].index(interface.stability_policy)
      i += 1
      if i == 0:
        warn(_("Unknown stability policy %s"), interface.stability_policy)
    else:
      i = 0
    stability.set_active(i)

    def set_stability_policy(combo):
      i = stability.get_active()
      if i == 0:
        new_stability = None
      else:
        name = stability.get_model()[i][0].lower()
        new_stability = stability_levels[name]
      interface.set_stability_policy(new_stability)
      writer.save_interface(interface)
      policy.recalculate()
    stability.connect('changed', set_stability_policy)

    self.use_list = ImplementationList(policy, interface, widgets)

    self.update_list()

    feeds.tv.grab_focus()

    def updated():
      self.update_list()
      feeds.updated()
      self.shade_compile()
    window.connect('destroy', lambda s: policy.watchers.remove(updated))
    policy.watchers.append(updated)
    self.shade_compile()

    if show_versions:
      notebook.next_page()

  def show(self):
    self.window.show()

  def destroy(self):
    self.window.destroy()
  
  def shade_compile(self):
    self.compile_button.set_sensitive(have_source_for(self.policy, self.interface))
  
  def update_list(self):
    ranked_items = self.policy.solver.details.get(self.interface, None)
    if ranked_items is None:
      # The Solver didn't get this far, but we should still display them!
      ranked_items = [(impl, _("(solve aborted before here)"))
          for impl in self.interface.implementations.values()]
    # Always sort by version
    ranked_items.sort()
    self.use_list.set_items(ranked_items)

@tasks.async
def add_remote_feed(policy, parent, interface):
  try:
    d = gtk.MessageDialog(parent, 0, gtk.MESSAGE_QUESTION, gtk.BUTTONS_CANCEL,
      _('Enter the URL of the new source of implementations of this interface:'))
    d.add_button(gtk.STOCK_ADD, gtk.RESPONSE_OK)
    d.set_default_response(gtk.RESPONSE_OK)
    entry = gtk.Entry()

    align = gtk.VBox(False, 0)
    align.set_border_width(4)
    align.add(entry)
    d.vbox.pack_start(align)
    entry.set_activates_default(True)

    entry.set_text('')

    d.vbox.show_all()

    error_label = gtk.Label('')
    error_label.set_padding(4, 4)
    align.pack_start(error_label)

    d.show()

    def error(message):
      if message:
        error_label.set_text(message)
        error_label.show()
      else:
        error_label.hide()

    while True:
      got_response = DialogResponse(d)
      yield got_response
      tasks.check(got_response)
      resp = got_response.response

      error(None)
      if resp == gtk.RESPONSE_OK:
        try:
          url = entry.get_text()
          if not url:
            raise zeroinstall.SafeException(_('Enter a URL'))
          fetch = policy.fetcher.download_and_import_feed(url, iface_cache)
          if fetch:
            d.set_sensitive(False)
            yield fetch
            d.set_sensitive(True)
            tasks.check(fetch)

            iface = iface_cache.get_interface(url)

            d.set_sensitive(True)
            if not iface.name:
              error(_('Failed to read interface'))
              return
            if not iface.feed_for:
              error(_("Feed '%(feed)s' is not a feed for '%(feed_for)s'.") % {'feed': iface.get_name(), 'feed_for': interface.get_name()})
            elif interface.uri not in iface.feed_for:
              error(_("This is not a feed for '%(uri)s'.\nOnly for:\n%(feed_for)s") %
                {'uri': interface.uri, 'feed_for': '\n'.join(iface.feed_for)})
            elif iface.uri in [f.uri for f in interface.feeds]:
              error(_("Feed from '%s' has already been added!") % iface.uri)
            else:
              interface.extra_feeds.append(Feed(iface.uri, arch = None, user_override = True))
              writer.save_interface(interface)
              d.destroy()
              policy.recalculate()
        except zeroinstall.SafeException, ex:
          error(str(ex))
      else:
        d.destroy()
        return
  except Exception, ex:
    import traceback
    traceback.print_exc()
    policy.handler.report_error(ex)

def add_local_feed(policy, interface):
  chooser = gtk.FileChooserDialog(_('Select XML feed file'), action=gtk.FILE_CHOOSER_ACTION_OPEN, buttons=(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_OPEN, gtk.RESPONSE_OK))
  def ok(feed):
    from zeroinstall.injector import reader
    try:
      feed_targets = policy.get_feed_targets(feed)
      if interface not in feed_targets:
        raise Exception(_("Not a valid feed for '%(uri)s'; this is a feed for:\n%(feed_for)s") %
            {'uri': interface.uri,
            'feed_for': '\n'.join([f.uri for f in feed_targets])})
      if interface.get_feed(feed):
        dialog.alert(None, _('This feed is already registered.'))
      else:
        interface.extra_feeds.append(Feed(feed, user_override = True, arch = None))

      writer.save_interface(interface)
      chooser.destroy()
      reader.update_from_cache(interface)
      policy.recalculate()
    except Exception, ex:
      dialog.alert(None, _("Error in feed file '%(feed)s':\n\n%(exception)s") % {'feed': feed, 'exception': str(ex)})

  def check_response(widget, response):
    if response == gtk.RESPONSE_OK:
      ok(widget.get_filename())
    elif response == gtk.RESPONSE_CANCEL:
      widget.destroy()

  chooser.connect('response', check_response)
  chooser.show()

def edit(policy, interface, show_versions = False):
  assert isinstance(interface, Interface)
  if interface in _dialogs:
    _dialogs[interface].destroy()
  _dialogs[interface] = Properties(policy, interface, show_versions)
  _dialogs[interface].show()

properties_help = help_box.HelpBox(_("Injector Properties Help"),
(_('Interface properties'), '\n' +
_("""This window displays information about an interface. There are two tabs at the top: \
Feeds shows the places where the injector looks for implementations of the interface, while \
Versions shows the list of implementations found (from all feeds) in order of preference.""")),

(_('The Feeds tab'), '\n' +
_("""At the top is a list of feeds. By default, the injector uses the full name of the interface \
as the default feed location (so if you ask it to run the program "http://foo/bar.xml" then it will \
by default get the list of versions by downloading "http://foo/bar.xml".

You can add and remove feeds using the buttons on the right. The main feed may also add \
some extra feeds itself. If you've checked out a developer version of a program, you can use \
the 'Add Local Feed...' button to let the injector know about it, for example.

Below the list of feeds is a box describing the selected one:

- At the top is its short name.
- Below that is the address (a URL or filename).
- 'Last upstream change' shows the version of the cached copy of the interface file.
- 'Last checked' is the last time a fresh copy of the upstream interface file was \
downloaded.
- Then there is a longer description of the interface.""")),

(_('The Versions tab'), '\n' +
_("""This tab shows a list of all known implementations of the interface, from all the feeds. \
The columns have the following meanings:

Version gives the version number. High-numbered versions are considered to be \
better than low-numbered ones.

Released gives the date this entry was added to the feed.

Stability is 'stable' if the implementation is believed to be stable, 'buggy' if \
it is known to contain serious bugs, and 'testing' if its stability is not yet \
known. This information is normally supplied and updated by the author of the \
software, but you can override their rating by right-clicking here (overridden \
values are shown in upper-case). You can also use the special level 'preferred'.

Fetch indicates how much data needs to be downloaded to get this version if you don't \
have it. If the implementation has already been downloaded to your computer, \
it will say (cached). (local) means that you installed this version manually and \
told Zero Install about it by adding a feed. (package) means that this version \
is provided by your distribution's package manager, not by Zero Install. \
In off-line mode, only cached implementations are considered for use.

Arch indicates what kind of computer system the implementation is for, or 'any' \
if it works with all types of system.""") + '\n'),
(_('Sort order'), '\n' +
_("""The implementations are ordered by version number (highest first), with the \
currently selected one in bold. This is the "best" usable version.

Unusable ones are those for incompatible \
architectures, those marked as 'buggy' or 'insecure', versions explicitly marked as incompatible with \
another interface you are using and, in off-line mode, uncached implementations. Unusable \
implementations are shown crossed out.

For the usable implementations, the order is as follows:

- Preferred implementations come first.

- Then, if network use is set to 'Minimal', cached implementations come before \
non-cached.

- Then, implementations at or above the selected stability level come before all others.

- Then, higher-numbered versions come before low-numbered ones.

- Then cached come before non-cached (for 'Full' network use mode).""") + '\n'),

(_('Compiling'), '\n' +
_("""If there is no binary available for your system then you may be able to compile one from \
source by clicking on the Compile button. If no source is available, the Compile button will \
be shown shaded.""") + '\n'))
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.