EventGhost/EventGhost

View on GitHub
eg/Classes/AddPluginDialog.py

Summary

Maintainability
D
1 day
Test Coverage
# -*- coding: utf-8 -*-
#
# This file is part of EventGhost.
# Copyright © 2005-2020 EventGhost Project <http://www.eventghost.net/>
#
# EventGhost 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.
#
# EventGhost 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 General Public License for
# more details.
#
# You should have received a copy of the GNU General Public License along
# with EventGhost. If not, see <http://www.gnu.org/licenses/>.

import wx

# Local imports
import eg

KIND_TAGS = ["other", "remote", "program", "external"]

class Config(eg.PersistentData):
    position = None
    size = (640, 450)
    splitPosition = 240
    lastSelection = None
    collapsed = set()


class Text(eg.TranslatableStrings):
    title = "Add Plugin..."
    noInfo = "No information available."
    noMultiloadTitle = "No multiload possible"
    noMultiload = (
        "This plugin doesn't support multiload and you already have one "
        "instance of this plugin in your configuration."
    )
    otherPlugins = "General Plugins"
    remotePlugins = "Input Devices"
    programPlugins = "Software Control"
    externalPlugins = "Hardware Control"
    author = "Author:"
    version = "Version:"
    descriptionBox = "Description"


class AddPluginDialog(eg.TaskletDialog):
    instance = None

    def CheckMultiload(self):
        if not self.checkMultiLoad:
            return True
        info = self.resultData
        if not info:
            return True
        if info.canMultiLoad:
            return True
        if any((plugin.info.path == info.path) for plugin in eg.pluginList):
            eg.MessageBox(
                Text.noMultiload,
                Text.noMultiloadTitle,
                style=wx.ICON_EXCLAMATION
            )
            return False
        else:
            return True

    @eg.LogItWithReturn
    def Configure(self, parent, checkMultiLoad=True, title=None):
        if title is None:
            title = Text.title
        self.checkMultiLoad = checkMultiLoad
        if self.__class__.instance:
            self.__class__.instance.Raise()
            return
        self.__class__.instance = self

        self.resultData = None

        eg.TaskletDialog.__init__(
            self,
            parent,
            -1,
            title,
            style=wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER
        )

        splitterWindow = wx.SplitterWindow(
            self,
            style=(
                wx.SP_LIVE_UPDATE |
                wx.CLIP_CHILDREN |
                wx.NO_FULL_REPAINT_ON_RESIZE
            )
        )

        self.treeCtrl = treeCtrl = wx.TreeCtrl(
            splitterWindow,
            style=(
                wx.TR_SINGLE |
                wx.TR_HAS_BUTTONS |
                wx.TR_HIDE_ROOT |
                wx.TR_LINES_AT_ROOT
            )
        )

        treeCtrl.SetMinSize((170, 200))

        imageList = wx.ImageList(16, 16)
        imageList.Add(eg.Icons.PLUGIN_ICON.GetBitmap())
        imageList.Add(eg.Icons.FOLDER_ICON.GetBitmap())
        treeCtrl.SetImageList(imageList)

        root = treeCtrl.AddRoot("")
        typeIds = {
            KIND_TAGS[0]: treeCtrl.AppendItem(
                root, getattr(Text, KIND_TAGS[0] + "Plugins"), 1
            ),
            KIND_TAGS[1]: treeCtrl.AppendItem(
                root, getattr(Text, KIND_TAGS[1] + "Plugins"), 1
            ),
            KIND_TAGS[2]: treeCtrl.AppendItem(
                root, getattr(Text, KIND_TAGS[2] + "Plugins"), 1
            ),
            KIND_TAGS[3]: treeCtrl.AppendItem(
                root, getattr(Text, KIND_TAGS[3] + "Plugins"), 1
            ),
        }
        self.typeIds = typeIds
        itemToSelect = typeIds[KIND_TAGS[0]]

        for info in eg.pluginManager.GetPluginInfoList():
            if info.kind in ("hidden", "core"):
                continue
            if info.icon and info.icon != eg.Icons.PLUGIN_ICON:
                idx = imageList.Add(
                    eg.Icons.PluginSubIcon(info.icon).GetBitmap()
                )
            else:
                idx = 0

            treeId = treeCtrl.AppendItem(typeIds[info.kind], info.name, idx)
            if not info.valid:
                treeCtrl.SetItemTextColour(treeId, eg.colour.pluginError)
            treeCtrl.SetPyData(treeId, info)
            if info.path == Config.lastSelection:
                itemToSelect = treeId

        for kind, treeId in typeIds.iteritems():
            if kind in Config.collapsed:
                treeCtrl.Collapse(treeId)
            else:
                treeCtrl.Expand(treeId)

        treeCtrl.ScrollTo(itemToSelect)

        def OnCmdExport(dummyEvent=None):
            info = self.treeCtrl.GetPyData(self.treeCtrl.GetSelection())
            if info:
                eg.PluginInstall.Export(info)
        menu = wx.Menu()
        menuId = wx.NewId()
        menu.Append(menuId, eg.text.MainFrame.Menu.Export)
        self.Bind(wx.EVT_MENU, OnCmdExport, id=menuId)
        self.contextMenu = menu
        self.Bind(wx.EVT_TREE_ITEM_RIGHT_CLICK, self.OnItemRightClick)

        rightPanel = wx.Panel(splitterWindow)
        rightSizer = wx.BoxSizer(wx.VERTICAL)
        rightPanel.SetSizer(rightSizer)

        self.nameText = nameText = wx.StaticText(rightPanel)
        nameText.SetFont(wx.Font(14, wx.SWISS, wx.NORMAL, wx.FONTWEIGHT_BOLD))
        rightSizer.Add(nameText, 0, wx.EXPAND | wx.LEFT | wx.BOTTOM, 5)

        subSizer = wx.FlexGridSizer(2, 2)
        self.authorLabel = wx.StaticText(rightPanel, label=Text.author)
        subSizer.Add(self.authorLabel)
        self.authorText = wx.StaticText(rightPanel)
        subSizer.Add(self.authorText, 0, wx.EXPAND | wx.LEFT, 5)
        self.versionLabel = wx.StaticText(rightPanel, label=Text.version)
        subSizer.Add(self.versionLabel)
        self.versionText = wx.StaticText(rightPanel)
        subSizer.Add(self.versionText, 0, wx.EXPAND | wx.LEFT, 5)
        rightSizer.Add(subSizer, 0, wx.EXPAND | wx.LEFT | wx.BOTTOM, 5)

        staticBoxSizer = wx.StaticBoxSizer(
            wx.StaticBox(rightPanel, label=Text.descriptionBox)
        )

        self.descrBox = eg.HtmlWindow(rightPanel)
        staticBoxSizer.Add(self.descrBox, 1, wx.EXPAND)

        rightSizer.Add(staticBoxSizer, 1, wx.EXPAND | wx.LEFT, 5)

        splitterWindow.SplitVertically(self.treeCtrl, rightPanel)
        splitterWindow.SetMinimumPaneSize(60)
        splitterWindow.SetSashGravity(0.0)
        splitterWindow.UpdateSize()

        self.buttonRow = eg.ButtonRow(self, (wx.ID_OK, wx.ID_CANCEL), True)
        self.okButton = self.buttonRow.okButton
        self.okButton.Enable(False)

        mainSizer = wx.BoxSizer(wx.VERTICAL)
        mainSizer.Add(splitterWindow, 1, wx.EXPAND | wx.ALL, 5)
        mainSizer.Add(self.buttonRow.sizer, 0, wx.EXPAND)

        self.SetSizerAndFit(mainSizer)
        #minSize = mainSizer.GetMinSize()
        #self.SetMinSize(minSize)
        self.SetSize(Config.size)
        splitterWindow.SetSashPosition(Config.splitPosition)
        if Config.position:
            self.SetPosition(Config.position)
        treeCtrl.Bind(wx.EVT_TREE_SEL_CHANGED, self.OnSelectionChanged)
        treeCtrl.Bind(wx.EVT_TREE_ITEM_ACTIVATED, self.OnItemActivated)
        treeCtrl.SelectItem(itemToSelect)


# -------- This code is for setting the use GUID instead of XmlIdLink ---------
        self.click_count = 0

        def on_left_down(evt):
            x, y = evt.GetPosition()
            width, height = self.GetClientSize()

            start_x = width - 20
            stary_y = 0

            stop_x = start_x + 20
            stop_y = stary_y + 20

            if stop_x > x > start_x and stop_y > y > stary_y:
                if not self.click_count:
                    self.CaptureMouse()

            start_x = 0
            stary_y = height - 20

            stop_x = start_x + 20
            stop_y = stary_y + 20

            if stop_x > x > start_x and stop_y > y > stary_y:
                if self.click_count:
                    self.CaptureMouse()

            evt.Skip()

        def on_left_up(evt):
            if self.HasCapture():

                self.ReleaseMouse()
                self.click_count += 1

                if self.click_count == 2:
                    self.click_count = 0
                    dialog = eg.MessageDialog(
                        parent=None,
                        message=(
                            'Warning: This process cannot be undone so make\n'
                            '                  a backup copy of your save file now.\n\n'
                            'This process will modify and save all EventGhost Data!!\n'
                            'Enable using GUID\'s?\n\n'
                        ),
                        style=wx.YES_NO | wx.STAY_ON_TOP
                    )
                    if dialog.ShowModal() == wx.ID_YES:
                        eg.useTreeItemGUID = True
                        eg.document.SetIsDirty(True)
                        eg.document.Save()
                        eg.config.Save()

                    dialog.Destroy()

            evt.Skip()

        if eg.useTreeItemGUID is False:
            self.Bind(wx.EVT_LEFT_DOWN, on_left_down)
            self.Bind(wx.EVT_LEFT_UP, on_left_up)

# -----------------------------------------------------------------------------

        while self.Affirmed():
            if self.CheckMultiload():
                self.SetResult(self.resultData)
        Config.size = self.GetSizeTuple()
        Config.position = self.GetPositionTuple()
        Config.splitPosition = splitterWindow.GetSashPosition()
        Config.collapsed = set(
            kind for kind, treeId in typeIds.iteritems()
            if not treeCtrl.IsExpanded(treeId)
        )
        self.__class__.instance = None

    def OnItemActivated(self, event):
        item = self.treeCtrl.GetSelection()
        info = self.treeCtrl.GetPyData(item)
        if info is not None:
            #self.SetResult("huhu")
            self.OnOK(wx.CommandEvent())
            return
        event.Skip()

    def OnItemRightClick(self, event):
        """
        Handles wx.EVT_TREE_ITEM_RIGHT_CLICK events.
        """
        item = event.GetItem()
        self.treeCtrl.SelectItem(item)
        info = self.treeCtrl.GetPyData(item)
        if info:
            self.PopupMenu(self.contextMenu)

    def OnSelectionChanged(self, event):
        """
        Handle the wx.EVT_TREE_SEL_CHANGED events.
        """
        item = event.GetItem()
        self.resultData = info = self.treeCtrl.GetPyData(item)
        if info is None:
            name = self.treeCtrl.GetItemText(item)
            description = Text.noInfo
            self.authorLabel.SetLabel("")
            self.authorText.SetLabel("")
            self.versionLabel.SetLabel("")
            self.versionText.SetLabel("")
            self.okButton.Enable(False)
            event.Skip()
        else:
            name = info.name
            description = info.description
            self.descrBox.SetBasePath(info.path)
            self.authorLabel.SetLabel(Text.author)
            self.authorText.SetLabel(info.author.replace("&", "&&"))
            self.versionLabel.SetLabel(Text.version)
            self.versionText.SetLabel(info.version)
            self.okButton.Enable(True)
        self.nameText.SetLabel(name)
        url = info.url if info else None
        self.descrBox.SetPage(eg.Utils.AppUrl(description, url))