window.py :  » IDE » PIDA » pida-0.6beta3 » pida » services » window » 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 » IDE » PIDA 
PIDA » pida 0.6beta3 » pida » services » window » window.py
# -*- coding: utf-8 -*-
"""
    :copyright: 2005-2008 by The PIDA Project
    :license: GPL 2 or later (see README/COPYING/LICENSE)
"""

import os
import gtk
import string
import simplejson
from functools import partial

# PIDA Imports
from pida.core.service import Service
from pida.core.commands import CommandsConfig
from pida.core.events import EventsConfig
from pida.core.options import OptionsConfig,Color
from pida.core.actions import ActionsConfig
from pida.core.actions import TYPE_NORMAL,TYPE_TOGGLE,TYPE_REMEMBER_TOGGLE,TYPE_MENUTOOL
from pida.core.document import Document
from pida.core.features import FeaturesConfig
from pida.core.environment import workspace_name,settings_dir

# locale
from pida.core.locale import Locale
locale = Locale('window')
_ = locale.gettext



class ActionWindowMapping(list):
    """
    Specialised mapping for persitant shortcuts on plugin windows
    """
    def __init__(self, svc):
        self.svc = svc
        self._actions = {}
        super(ActionWindowMapping, self).__init__()

    @staticmethod
    def _genkey(key):
        """Returns the key for a action"""
        return 'window_config_%s' %key.replace(".", "_")

    def add(self, config):
        """
        Add a new shortcut for focusing a window.
        Get the shorcut from the window-config
        """
        self.append(config)
        keya = self._genkey(config.key)
        curshort = self.svc.actions.get_extra_value('window-config').\
                                                                get(keya, '')

        act = self.svc.actions.create_action(
            keya,
            TYPE_NORMAL,
            "Focus %s" %_(config.label_text),
            config.description or _('Focus %s window') %_(config.label_text),
            "",
            self.svc.actions.on_focus_window,
            config.default_shortcut,
            global_=True
        )
        act.key = config.key
        act.visible_action = config.action
        self._actions[config.key] = act
        self.svc.actions.set_value(keya, curshort)
        # make the shortcuts update to reflect change
        self.svc.boss.get_service('shortcuts').update()

    def remove(self, config):
        """Unregister a WindowConfig"""
        # unregister action
        self.svc.actions.remove_action(self._actions[config.key])

        del self._actions[config.key]
        opt = self.svc.actions.get_option(self._genkey(config.key))
        self.svc.actions.remove_option(opt)
        #self.remove(config)
        self.svc.boss.get_service('shortcuts').update()


class WindowCommandsConfig(CommandsConfig):

    def add_view(self, paned, view, removable=True, present=True, detachable=True):
        self.svc.window.add_view(paned, view, removable, present, detachable=detachable)
        self.svc.save_state()

    def add_detached_view(self, paned, view, size=(500,400)):
        self.add_view(paned, view)
        self.detach_view(view, size)
        self.svc.save_state()

    def close_focus_pane(self):
        pane = self.svc.window.get_focus_pane()
        if pane:
            if pane.view.can_be_closed() and pane.view:
                self.remove_view(pane.view)

    def toggle_sticky_pane(self):
        pane = self.svc.window.get_focus_pane()
        if pane:
            self.svc.window.paned.set_params(
                    pane, 
                    keep_on_top=not pane.get_params().keep_on_top)

    def remove_view(self, view):
        self.svc.window.remove_view(view)
        self.svc.save_state()

    def detach_view(self, view, size):
        self.svc.window.detach_view(view, size)
        self.svc.save_state()

    def present_view(self, view):
        self.svc.window.present_view(view)
        self.svc.save_state()

    def is_added(self, view):
        return view in self.svc.window

class WindowActionsConfig(ActionsConfig):

    def create_actions(self):
        self.register_extra_option('window-config', safe=False, notify=True,
                                   default={}, workspace=False)

        self.create_action(
            'show_toolbar',
            TYPE_TOGGLE,
            _('Show Toolbar'),
            _('Toggle the visible state of the toolbar'),
            'face-glasses',
            self.on_show_ui,
            '<Shift><Control>l',
        )

        self.create_action(
            'show_menubar',
            TYPE_TOGGLE,
            _('Show _Menubar'),
            _('Toggle the visible state of the menubar'),
            'face-glasses',
            self.on_show_ui,
            '<Shift><Control>u',
        )

        self.create_action(
            'fullscreen',
            TYPE_TOGGLE,
            _('F_ullscreen'),
            _('Toggle the fullscreen mode'),
            gtk.STOCK_FULLSCREEN,
            self.on_fullscreen,
            '<Shift>F11',
        )

        self.create_action(
            'max_editor',
            TYPE_TOGGLE,
            _('M_aximize Editor'),
            _('Maximizes the editor by hiding panels'),
            gtk.STOCK_FULLSCREEN,
            self.on_max_editor,
            'F11',
        )


        self.create_action(
            'switch_next_term',
            TYPE_NORMAL,
            _('Next _terminal'),
            _('Switch to the next terminal'),
            gtk.STOCK_GO_FORWARD,
            self.on_switch_next_term,
            '<Alt>Right',
            global_=True
        )

        self.create_action(
            'switch_prev_term',
            TYPE_NORMAL,
            _('Previous te_rminal'),
            _('Switch to the previous terminal'),
            gtk.STOCK_GO_BACK,
            self.on_switch_prev_term,
            '<Alt>Left',
            global_=True
        )

        self.create_action(
            'focus_terminal',
            TYPE_NORMAL,
            _('F_ocus terminal'),
            _('Focus terminal pane terminal'),
            'terminal',
            self.on_focus_terminal,
            '<Shift><Control>i',
            global_=True
        )

        self.create_action(
            'close_pane',
            TYPE_NORMAL,
            _('Close Pane'),
            _('Close the current active pane'),
            gtk.STOCK_CLOSE,
            self.on_close_pane,
            '<Control>F4',
            global_=True
        )

        self.create_action(
            'toggle_sticky',
            TYPE_NORMAL,
            _('Toggle sticky'),
            _('Toggle the sticky button on current pane'),
            'pin',
            self.on_toggle_sticky,
            '',
            global_=True
        )

        self.create_action(
            'WindowMenu',
            TYPE_MENUTOOL,
            _('Win_dows'),
            _('Show window list'),
            'package_utilities',
            self.on_windows,
        )

    def on_focus_window(self, action):
        if action.visible_action and isinstance(action.visible_action, 
                                          (TYPE_TOGGLE, TYPE_REMEMBER_TOGGLE)):
                action.visible_action.set_active(True)
        self.svc.present_key_window(action.key)

    def on_windows(self, action):
        self.svc.create_window_list()

    def on_focus_terminal(self, action):
        self.svc.window.present_paned('Terminal')

    def on_switch_next_term(self, action):
        self.svc.window.switch_next_view('Terminal')

    def on_switch_prev_term(self, action):
        self.svc.window.switch_prev_view('Terminal')

    def on_close_pane(self, action):
        self.svc.cmd('close_focus_pane')

    def on_toggle_sticky(self, action):
        self.svc.cmd('toggle_sticky_pane')

    def on_fullscreen(self, action):
        self.svc.set_fullscreen(action.get_active())

    def on_max_editor(self, action):
        self.svc.set_max_editor(action.get_active())

    def on_show_ui(self, action):
        val = action.get_active()
        self.svc.set_opt(action.get_name(), val)
        getattr(self.svc, action.get_name())(val)

    def _on_option_change(self, option):
        # hacky highjacking to put the options into a extra config :-)
        self.svc.actions.get_extra_value('window-config')[option.name] = \
            option.value
        self.svc.actions.set_extra_value('window-config', 
            self.svc.actions.get_extra_value('window-config'))
        # call normal callback
        self._set_action_keypress_from_option(option)

    def _create_key_option(self, act, name, label, tooltip, accel, global_=False):
        opt = super(WindowActionsConfig, self)._create_key_option(act, 
                                            name, label, tooltip, accel, global_=global_)

        if name[:14] == 'window_config_':
            # we highjack the callback on the external defined options
            # so we can set the extra option value so it gets persistent saved
            opt.callback = self._on_option_change

class WindowEvents(EventsConfig):

    def subscribe_all_foreign(self):
        self.subscribe_foreign('buffer', 'document-changed',
            self.on_document_changed)
        self.subscribe_foreign('editor', 'started',
            self.on_editor_started)

    def on_document_changed(self, document):
        self.svc.update_title(document=document)

    def on_editor_started(self):
        self.svc.boss.hide_splash()
        self.svc.window.show()


class WindowFeatures(FeaturesConfig):
    def create(self):
        nmapping = partial(ActionWindowMapping, self.svc)
        self.publish_special(
            nmapping,
            'window-config',
        )


        #self.publish('window-config')
        #self.subscribe('window-config', self.on_window_config)



class WindowOptionsConfig(OptionsConfig):

    def create_options(self):
        self.create_option(
            'show_toolbar',
            _('Show the toolbar'),
            bool,
            True,
            _('Whether the main toolbar will be shown'),
            self.on_show_ui,
        )

        self.create_option(
            'show_menubar',
            _('Show the menubar'),
            bool,
            True,
            _('Whether the main menubar will be shown'),
            self.on_show_ui,
        )

        self.create_option(
            'window_title',
            _('Window title'),
            str,
            'Pida - $workspace - $filepath',
            _('Title template for the pida window.\n'
              '$basename : Filename of Document - $filepath : Full filepath \n'
              '$directory : Directory if file - $workspace : Workspace name \n'
              '$project_path - $project_name'),
            self.on_title_change,
        )

        self.create_option(
            'project_color',
            _('Project color'),
            Color,
            '#600060',
            _('The color projects shall have in PIDA'),
            self.on_color_change,
        )

        self.create_option(
            'no_project_color',
            _('No project color'),
            Color,
            '#CB4444',
            _('The color projects shall have in PIDA'),
            self.on_color_change,
        )

        self.create_option(
            'directory_color',
            _('Directory color'),
            Color,
            '#0000c0',
            _('The color directories shall have in PIDA'),
            self.on_color_change,
        )

    def on_show_ui(self, option):
        self.svc.get_action(option.name).set_active(option.value)

    def on_color_change(self, option):
        self.svc.update_colors()

    def on_title_change(self, *args):
        self.svc._title_template = None
        self.svc.update_title()

# Service class
class Window(Service):
    """The PIDA Window Manager"""

    commands_config = WindowCommandsConfig
    options_config = WindowOptionsConfig
    actions_config = WindowActionsConfig
    events_config = WindowEvents
    features_config = WindowFeatures
    
    def pre_start(self):
        self._title_template = None
        self._last_focus = None
        super(Window, self).pre_start()
        self.update_colors()
        self.state_config = os.path.join(settings_dir, 'workspaces', 
                                         workspace_name(), "window.state.json")
        self.restore_state(pre=True)

    def start(self):
        # Explicitly add the permanent views
        for service in ['project', 'filemanager', 'buffer']:
            view = self.boss.cmd(service, 'get_view')
            self.cmd('add_view', paned='Buffer', view=view, removable=False, present=False)
        self._fix_visibilities()
        self.update_colors()
        self._window_list_id = self.boss.window.create_merge_id()
        self._action_group = gtk.ActionGroup('window_list')
        self.boss.window._uim._uim.insert_action_group(self._action_group, -1)
        self.restore_state()
        self.window.paned.connect('config-changed', self.save_state)
        self.window.paned.connect('pane-attachment-changed', self._on_pane_detachment)

    def pre_stop(self):
        self.save_state()
        return True

    def stop(self):
        self.save_state()

    def restore_state(self, pre=False):
        try:
            fp = open(self.state_config, "r")
        except (OSError, IOError), e:
            self.log("Can't open state file %s" %self.state_config)
            return
        data = simplejson.load(fp)

        if pre:
            # in pre mode we restore the paned config and the window position/size, etc
            self.boss.window.paned.set_config(data.get('panedstate', ''))
            # restore window size and position
            if data.has_key('pida_main_window'):
                cdata = data['pida_main_window']
                # test if data is valid. we don't place the window where it
                # is not fully visible
                try:
                    height = max(int(cdata['height']), 100)
                    width = max(int(cdata['width']), 100)
                    x = max(int(cdata['x']), 0)
                    y = max(int(cdata['y']), 0)
                    if x + width <= gtk.gdk.screen_width() and \
                       y + height <= gtk.gdk.screen_height():
                        self.boss.window.resize(width, height)
                        self.boss.window.move(x, y)
                    else:
                        self.log.debug("Won't restore window size outside screen")
                except (ValueError, KeyError):
                    pass
            return

        for service in self.boss.get_services():
            if not data.has_key(service.get_name()):
                continue
            for action in service.actions.list_actions():
                if isinstance(action, TYPE_REMEMBER_TOGGLE):
                    try:
                        action.set_active(data[service.get_name()][action.get_name()])
                    except KeyError:
                        pass

    def save_state(self, *args):
        if not self.started:
            return
        data = {}
        data['panedstate'] = self.boss.window.paned.get_config()
        # save window size and position
        size = self.boss.window.get_size()
        pos = self.boss.window.get_position()
        data['pida_main_window'] = {
            "width": size[0],
            "height": size[1],
            "x": pos[0],
            "y": pos[1],
        }
        for service in self.boss.get_services():
            cur = {}
            if not hasattr(service, "actions"):
                continue
            for action in service.actions.list_actions():
                if isinstance(action, TYPE_REMEMBER_TOGGLE):
                    cur[action.get_name()] = action.props.active
            if cur:
                data[service.get_name()] = cur
        
        try:
            fp = open(self.state_config, "w")
        except (OSError, IOError), e:
            self.log("Can't open state file %s" %self.state_config)
            return
        simplejson.dump(data, fp, indent=4)

    def _on_pane_detachment(self, bigpaned, pane, detached):
        if detached:
            # thanks gtk for not letting me test if accel is already added
            win = pane.get_child().get_toplevel()
            if not getattr(win, '_pida_accel_added', False):
                win.add_accel_group(self.actions.global_accelerator_group)
                win._pida_accel_added = True

    def update_colors(self):
        # set the colors of Document
        Document.markup_directory_color = self.opt('directory_color')
        Document.markup_project_color = self.opt('project_color')
        Document.markup_color_noproject = self.opt('no_project_color')

    def update_title(self, document=None):
        if self._title_template is None:
            self._title_template = string.Template(self.opt('window_title'))
        if document is None:
            document = self.boss.cmd('buffer', 'get_current')
        
        subs = {'basename': document.basename or _('New Document'),
                'filepath': document.filename or _('New Document'),
                'directory': document.directory or '',
                'workspace': workspace_name(),
                'project_path': document.project and document.project.data_dir or '',
                'project_name': document.project_name
               }
        
        self.window.set_title(self._title_template.safe_substitute(subs))
        

    def _fix_visibilities(self):
        for name in ['show_toolbar', 'show_menubar']:
            val = self.opt(name)
            self.get_action(name).set_active(val)
            getattr(self, name)(val)

    def show_toolbar(self, visibility):
        self.window.set_toolbar_visibility(visibility)

    def show_menubar(self, visibility):
        self.window.set_menubar_visibility(visibility)

    def set_fullscreen(self, var):
        if var:
            self.boss.window.fullscreen()
        else:
            self.window.unfullscreen()


    def set_max_editor(self, var):
        if var:
            # shall we do a weak ref here ?
            self._last_focus = self.boss.window.get_focus()
            self.window.set_fullscreen(var)
            self.boss.editor.cmd('grab_focus')
        else:
            self.window.set_fullscreen(var)
            if self._last_focus:
                try:
                    # this maight fail due various reasons, like
                    # the window was destroyed etc
                    self._last_focus.grab_focus()
                except: 
                    pass

    def get_fullscreen(self, var):
        return self.window.get_fullscreen()

    def _on_window_action(self, action, view):
        self.boss.window.present_view(view)

    def _on_doc_action(self, action, doc):
        self.boss.get_service('buffer').view_document(doc)

    def present_key_window(self, key):
        for pane in self.boss.window.paned.list_panes(every=True):
            if pane.key == key:
                self.cmd('present_view', view=pane)
                return

    def create_window_list(self):
        # update the window menu list
        # clean up the old list
        self.boss.window.remove_uidef(self._window_list_id)
        for action in self._action_group.list_actions():
            self._action_group.remove_action(action)

        i = 0
        # add panels to list. they are sorted after the paned positions and
        # therefor good
        for pane in self.boss.window.paned.list_panes(every=True):
            action_name = "show_window_%s" %i
            act = gtk.Action(action_name,
                "_%s" %pane.view.label_text,
                '',
                '')
            act.connect('activate', self._on_window_action, pane.view)
            self._action_group.add_action(act)
            self.boss.window._uim._uim.add_ui(
                self._window_list_id,
                "ui/menubar/AddMenu/WindowMenu/window_list", 
                "_%s" %pane.view.label_text, 
                action_name, 
                gtk.UI_MANAGER_MENUITEM, 
                False)            #mi = act.create_menu_item()
            i += 1
        # add documents to list
        docs = list(self.boss.get_service('buffer').get_documents().itervalues())
        # we sort the docs list alphabeticly as its easier for the eye to navigate
        docs.sort(lambda x,y: cmp(unicode(x).lower(), unicode(y).lower()))
        for doc in docs:
            action_name = "show_window_%s" %i
            act = gtk.Action(action_name,
                unicode(doc),
                '',
                '')
            act.connect('activate', self._on_doc_action, doc)
            self._action_group.add_action(act)
            self.boss.window._uim._uim.add_ui(
                self._window_list_id,
                "ui/menubar/AddMenu/WindowMenu/buffer_list", 
                unicode(doc), 
                action_name, 
                gtk.UI_MANAGER_MENUITEM, 
                False)
            i += 1
        return None

# Required Service attribute for service loading
Service = Window



# vim:set shiftwidth=4 tabstop=4 expandtab textwidth=79:
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.