File: helpers.py

package info (click to toggle)
frescobaldi 3.0.0~git20161001.0.eec60717%2Bds1-2
  • links: PTS, VCS
  • area: main
  • in suites: stretch
  • size: 19,792 kB
  • ctags: 5,843
  • sloc: python: 37,853; sh: 180; makefile: 69
file content (138 lines) | stat: -rw-r--r-- 4,298 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
# This file is part of the Frescobaldi project, http://www.frescobaldi.org/
#
# Copyright (c) 2008 - 2014 by Wilbert Berendsen
#
# This program 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.
#
# This program 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 this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
# See http://www.gnu.org/licenses/ for more information.

"""
Helper application stuff.
"""


import os
import re
import subprocess
import sys

from PyQt5.QtCore import QSettings
from PyQt5.QtGui import QDesktopServices
from PyQt5.QtWidgets import QMessageBox

def shell_split(cmd):
    """Split a string like the UNIX shell, returning a list.
    
    Double quoted parts are kept together with the quotes removed.
    
    """
    # remove double quotes, keeping quoted parts together
    # (because shlex does not yet work with unicode...)
    return [item.replace('"', '') for item in 
        re.findall(r'[^\s"]*"[^"]*"[^\s"]*|[^\s"]+', cmd)]


def command(type):
    """Returns the command for the specified type as a list.
    
    Returns None if no command was specified.
    
    """
    cmd = QSettings().value("helper_applications/" + type, "")
    if not cmd:
        return
    
    if os.path.isabs(cmd) and os.access(cmd, os.X_OK):
        return [cmd]

    return shell_split(cmd)


def openUrl(url, type="browser"):
    """Opens the specified QUrl, using the specified type."""
    # be sure to pick a suitable type
    if url.scheme() == "mailto":
        type = "email"
    elif type == "browser" and url.toLocalFile():
        ext = os.path.splitext(url.toLocalFile())[1].lower()
        if os.path.isdir(url.toLocalFile()):
            type = "directory"
        elif ext == '.pdf':
            type = "pdf"
        elif ext in ('.png', '.jpg', '.jpeg'):
            type = "image"
        elif ext in ('.midi', '.mid'):
            type = "midi"
    
    # get the command
    cmd = command(type)
    if not cmd:
        if type != "shell":
            QDesktopServices.openUrl(url)
            return
        for cmd in terminalCommands():
            break # get the first
    
    prog = cmd.pop(0)
    
    workdir = None
    if url.toLocalFile():
        workdir = url.toLocalFile()
        if type != "shell":
            workdir = os.path.dirname(workdir)
    
    if any('$f' in a or '$u' in a for a in cmd):
        cmd = [a.replace('$u', url.toString())
                if '$u' in a else a.replace('$f', url.toLocalFile())
                for a in cmd]
    elif type in ("browser", "email"):
        cmd.append(url.toString())
    elif type != "shell":
        cmd.append(url.toLocalFile())
    
    try:
        subprocess.Popen([prog] + cmd, cwd=workdir)
    except OSError:
        QMessageBox.critical(None, _("Error"), _(
            "Could not start {program}.\n"
            "Please check path and permissions.").format(program=prog))


def terminalCommands():
    """Yields suitable commands to open a terminal/shell window.
    
    There is always yielded at least one, which is suitable as default.
    
    """
    if os.name == "nt":
        yield ['cmd.exe']
    elif sys.platform == 'darwin':
        yield ['open', '-a', 'Terminal', '$f']
    else:
        # find a default linux terminal
        paths = os.environ.get('PATH', os.defpath).split(os.pathsep)
        for cmd in (
            ['lxterminal', '--working-directory=$f'],
            ['xfce4-terminal', '--working-directory=$f'],
            ['konsole', '--workdir', '$f'],
            ['gnome-terminal', '--working-directory=$f'],
            ):
            for p in paths:
                if p:
                    prog = os.path.join(p, cmd[0])
                    if os.access(prog, os.X_OK):
                        yield cmd
        yield ['xterm']