reorder.py 4.63 KB
Newer Older
mathieui's avatar
mathieui committed
1 2 3 4 5 6 7 8 9 10 11 12 13
"""
``reorder`` plugin: Reorder the tabs according to a layout

Commands
--------

.. glossary::

    /reorder
        **Usage:** ``/reorder``

        Reorder the tabs according to the configuration.

14 15 16 17
    /save_order
        **Usage:** ``/save_order``

        Save the current tab order to the configuration.
mathieui's avatar
mathieui committed
18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60

Configuration
-------------

The configuration file must contain a section ``[reorder]`` and each option
must be formatted like ``[tab number] = [tab type]:[tab name]``.

For example:

.. code-block:: ini

    [reorder]
    1 = muc:toto@conference.example.com
    2 = muc:example@muc.example.im
    3 = dynamic:robert@example.org

The ``[tab number]`` must be at least ``1``; if the range is not entirely
covered, e.g.:

.. code-block:: ini

    [reorder]
    1 = muc:toto@conference.example.com
    3 = dynamic:robert@example.org

Poezio will insert gaps between the tabs in order to keep the specified
numbering (so in this case, there will be a tab 1, a tab 3, but no tab 2).


The ``[tab type]`` must be one of:

- ``muc`` (for multi-user chats)
- ``private`` (for chats with a specific user inside a multi-user chat)
- ``dynamic`` (for normal, dynamic conversations tabs)
- ``static`` (for conversations with a specific resource)

And finally, the ``[tab name]`` must be:

- For a type ``muc``, the bare JID of the room
- For a type ``private``, the full JID of the user (room JID with the username as a resource)
- For a type ``dynamic``, the bare JID of the contact
- For a type ``static``, the full JID of the contact
"""
61

62 63
from poezio import tabs
from poezio.decorators import command_args_parser
64
from poezio.plugin import BasePlugin
65
from poezio.config import config
mathieui's avatar
mathieui committed
66

67
TEXT_TO_TAB = {
mathieui's avatar
mathieui committed
68 69 70 71 72 73 74
    'muc': tabs.MucTab,
    'private': tabs.PrivateTab,
    'dynamic': tabs.DynamicConversationTab,
    'static': tabs.StaticConversationTab,
    'empty': tabs.GapTab
}

75 76 77 78 79 80 81 82
TAB_TO_TEXT = {
    tabs.MucTab: 'muc',
    tabs.DynamicConversationTab: 'dynamic',
    tabs.PrivateTab: 'private',
    tabs.StaticConversationTab: 'static',
    tabs.GapTab: 'empty'
}

mathieui's avatar
mathieui committed
83

mathieui's avatar
mathieui committed
84
def parse_config(tab_config):
mathieui's avatar
mathieui committed
85
    result = {}
mathieui's avatar
mathieui committed
86
    for option in tab_config.options('reorder'):
mathieui's avatar
mathieui committed
87 88 89 90
        if not option.isdecimal():
            continue
        pos = int(option)
        if pos in result or pos <= 0:
mathieui's avatar
mathieui committed
91
            return None
mathieui's avatar
mathieui committed
92

mathieui's avatar
mathieui committed
93
        typ, name = tab_config.get(option, default=':').split(':', maxsplit=1)
94
        if typ not in TEXT_TO_TAB:
mathieui's avatar
mathieui committed
95
            return None
96
        result[pos] = (TEXT_TO_TAB[typ], name)
mathieui's avatar
mathieui committed
97 98 99

    return result

mathieui's avatar
mathieui committed
100

101 102 103 104 105 106
def check_tab(tab):
    for cls, rep in TAB_TO_TEXT.items():
        if isinstance(tab, cls):
            return rep
    return ''

mathieui's avatar
mathieui committed
107

108 109 110 111 112 113 114 115 116 117
def parse_runtime_tablist(tablist):
    props = []
    i = 0
    for tab in tablist[1:]:
        i += 1
        result = check_tab(tab)
        if result:
            props.append((i, '%s:%s' % (result, tab.name)))
    return props

mathieui's avatar
mathieui committed
118

mathieui's avatar
mathieui committed
119 120
class Plugin(BasePlugin):
    def init(self):
mathieui's avatar
mathieui committed
121 122 123 124 125 126 127 128 129
        self.api.add_command(
            'reorder',
            self.command_reorder,
            help='Reorder all tabs using the pre-defined'
            ' layout from the configuration file.')
        self.api.add_command(
            'save_order',
            self.command_save_order,
            help='Save the current tab layout')
130 131 132 133 134 135 136

    @command_args_parser.ignored
    def command_save_order(self):
        conf = parse_runtime_tablist(self.core.tabs)
        for key, value in conf:
            self.config.set(key, value)
        self.api.information('Tab order saved', 'Info')
mathieui's avatar
mathieui committed
137 138 139 140 141 142 143 144 145 146

    @command_args_parser.ignored
    def command_reorder(self):
        """
        /reorder
        """
        tabs_spec = parse_config(self.config)
        if not tabs_spec:
            return self.api.information('Invalid reorder config', 'Error')

mathieui's avatar
mathieui committed
147 148
        old_tabs = self.core.tabs.get_tabs()
        roster = old_tabs.pop(0)
mathieui's avatar
mathieui committed
149

150 151
        create_gaps = config.get('create_gaps')

mathieui's avatar
mathieui committed
152
        new_tabs = [roster]
mathieui's avatar
mathieui committed
153 154
        last = 0
        for pos in sorted(tabs_spec):
155
            if create_gaps and pos > last + 1:
mathieui's avatar
mathieui committed
156 157 158
                new_tabs += [
                    tabs.GapTab(self.core) for i in range(pos - last - 1)
                ]
mathieui's avatar
mathieui committed
159
            cls, name = tabs_spec[pos]
mathieui's avatar
mathieui committed
160
            tab = self.core.tabs.by_name_and_class(name, cls=cls)
mathieui's avatar
mathieui committed
161 162 163 164 165
            if tab and tab in old_tabs:
                new_tabs.append(tab)
                old_tabs.remove(tab)
            else:
                self.api.information('Tab %s not found' % name, 'Warning')
166 167
                if create_gaps:
                    new_tabs.append(tabs.GapTab(self.core))
mathieui's avatar
mathieui committed
168 169 170 171 172 173
            last = pos

        for tab in old_tabs:
            if tab:
                new_tabs.append(tab)

mathieui's avatar
mathieui committed
174
        self.core.tabs.replace_tabs(new_tabs)
mathieui's avatar
mathieui committed
175
        self.core.refresh_window()