Initial project creation with Quickly!
This commit is contained in:
commit
3d16afe6bb
|
@ -0,0 +1,3 @@
|
||||||
|
project = mugshot
|
||||||
|
version = 12.08.1
|
||||||
|
template = ubuntu-application
|
|
@ -0,0 +1,36 @@
|
||||||
|
#!/usr/bin/python
|
||||||
|
# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
|
||||||
|
### BEGIN LICENSE
|
||||||
|
# This file is in the public domain
|
||||||
|
### END LICENSE
|
||||||
|
|
||||||
|
### DO NOT EDIT THIS FILE ###
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
|
||||||
|
import locale
|
||||||
|
locale.textdomain('mugshot')
|
||||||
|
|
||||||
|
# Add project root directory (enable symlink and trunk execution)
|
||||||
|
PROJECT_ROOT_DIRECTORY = os.path.abspath(
|
||||||
|
os.path.dirname(os.path.dirname(os.path.realpath(sys.argv[0]))))
|
||||||
|
|
||||||
|
python_path = []
|
||||||
|
if os.path.abspath(__file__).startswith('/opt'):
|
||||||
|
locale.bindtextdomain('mugshot', '/opt/extras.ubuntu.com/mugshot/share/locale')
|
||||||
|
syspath = sys.path[:] # copy to avoid infinite loop in pending objects
|
||||||
|
for path in syspath:
|
||||||
|
opt_path = path.replace('/usr', '/opt/extras.ubuntu.com/mugshot')
|
||||||
|
python_path.insert(0, opt_path)
|
||||||
|
sys.path.insert(0, opt_path)
|
||||||
|
os.putenv("XDG_DATA_DIRS", "%s:%s" % ("/opt/extras.ubuntu.com/mugshot/share/", os.getenv("XDG_DATA_DIRS", "/usr/local/share/:/usr/share/")))
|
||||||
|
if (os.path.exists(os.path.join(PROJECT_ROOT_DIRECTORY, 'mugshot'))
|
||||||
|
and PROJECT_ROOT_DIRECTORY not in sys.path):
|
||||||
|
python_path.insert(0, PROJECT_ROOT_DIRECTORY)
|
||||||
|
sys.path.insert(0, PROJECT_ROOT_DIRECTORY)
|
||||||
|
if python_path:
|
||||||
|
os.putenv('PYTHONPATH', "%s:%s" % (os.getenv('PYTHONPATH', ''), ':'.join(python_path))) # for subprocesses
|
||||||
|
|
||||||
|
import mugshot
|
||||||
|
mugshot.main()
|
|
@ -0,0 +1,10 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<schemalist gettext-domain="mugshot">
|
||||||
|
<schema id="net.launchpad.mugshot" path="/net/launchpad/mugshot/">
|
||||||
|
<key name="example" type="s">
|
||||||
|
<default>''</default>
|
||||||
|
<summary>Sample setting</summary>
|
||||||
|
<description>Longer description of this sample setting. Talk about allowed values and what it does.</description>
|
||||||
|
</key>
|
||||||
|
</schema>
|
||||||
|
</schemalist>
|
Binary file not shown.
After Width: | Height: | Size: 8.6 KiB |
|
@ -0,0 +1,74 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
width="64"
|
||||||
|
height="64.000008"
|
||||||
|
id="svg2"
|
||||||
|
version="1.1"
|
||||||
|
inkscape:version="0.48.0 r9654"
|
||||||
|
inkscape:export-filename="/home/daniel/Projects/test1/data/media/logo.png"
|
||||||
|
inkscape:export-xdpi="90"
|
||||||
|
inkscape:export-ydpi="90"
|
||||||
|
sodipodi:docname="logo1.svg">
|
||||||
|
<defs
|
||||||
|
id="defs4" />
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="base"
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1.0"
|
||||||
|
inkscape:pageopacity="0.0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:zoom="1"
|
||||||
|
inkscape:cx="37.013172"
|
||||||
|
inkscape:cy="128"
|
||||||
|
inkscape:document-units="px"
|
||||||
|
inkscape:current-layer="layer1"
|
||||||
|
showgrid="false"
|
||||||
|
fit-margin-top="0"
|
||||||
|
fit-margin-left="0"
|
||||||
|
fit-margin-right="0"
|
||||||
|
fit-margin-bottom="0"
|
||||||
|
showborder="false"
|
||||||
|
inkscape:window-width="1280"
|
||||||
|
inkscape:window-height="753"
|
||||||
|
inkscape:window-x="0"
|
||||||
|
inkscape:window-y="24"
|
||||||
|
inkscape:window-maximized="1" />
|
||||||
|
<metadata
|
||||||
|
id="metadata7">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<dc:title></dc:title>
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<g
|
||||||
|
inkscape:label="Layer 1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1"
|
||||||
|
transform="translate(-355.97817,-385.42867)">
|
||||||
|
<path
|
||||||
|
style="fill:#f37320"
|
||||||
|
d="m 384.83834,449.28391 c -8.14057,-0.84905 -15.49055,-4.63875 -20.99488,-10.8251 -8.42757,-9.47182 -10.28693,-23.7434 -4.58555,-35.19659 6.88824,-13.8374 22.76153,-20.85855 37.51104,-16.59205 11.98015,3.46543 20.6717,13.18933 22.83033,25.54204 0.67518,3.86376 0.42901,9.41585 -0.58713,13.24168 -2.42757,9.13998 -8.98351,17.01406 -17.44916,20.95748 -5.03786,2.34672 -11.35816,3.43226 -16.72465,2.87254 z"
|
||||||
|
id="path3061"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
<path
|
||||||
|
style="fill:#ffffff"
|
||||||
|
d="m 398.73202,394.34273 c -1.08285,0.0211 -2.15589,0.48165 -2.98979,1.42969 -1.18348,1.34547 -1.40418,2.71621 -0.71223,4.38281 1.03576,2.49465 3.94418,3.42259 6.13611,1.96094 1.67694,-1.11824 2.46376,-3.57017 1.65143,-5.14844 -0.89738,-1.74353 -2.5029,-2.65576 -4.08552,-2.625 z m -10.89472,4.5625 c -2.42555,0.0486 -5.06336,0.54882 -7.13793,1.41406 l -0.98616,0.41407 1.4401,2.58593 c 0.7934,1.42317 1.57848,2.58594 1.73753,2.58594 0.15904,0 1.00483,-0.20744 1.8784,-0.46094 1.11892,-0.32468 2.32043,-0.42761 4.07769,-0.34375 2.11554,0.10097 2.79469,0.26709 4.4612,1.08594 3.49728,1.7184 6.43694,5.49864 6.88747,8.85156 l 0.15654,1.14063 3.12284,0 3.12285,0 -0.18785,-1.35156 c -0.4425,-3.10716 -2.22228,-7.05351 -4.21857,-9.35157 -0.98973,-1.13933 -0.99683,-1.14194 -2.84891,-1.04687 -1.42823,0.0733 -2.1054,-0.0309 -2.95848,-0.46875 -1.4763,-0.75774 -2.64614,-2.0279 -3.10719,-3.375 -0.36828,-1.07602 -0.42039,-1.11073 -2.33235,-1.46094 -0.94616,-0.1733 -2.00467,-0.24083 -3.10718,-0.21875 z m -10.40166,3.29688 c -0.21996,-0.004 -1.37809,0.98671 -2.57497,2.20312 -2.13408,2.16892 -3.79668,4.8071 -4.58642,7.27344 -0.30595,0.95543 -0.27996,1.1251 0.27392,1.71094 2.02961,2.14667 2.13473,5.62909 0.23481,7.78906 l -0.82964,0.95312 0.57918,1.64063 c 0.31829,0.90395 0.99768,2.35651 1.51055,3.22656 0.98269,1.66709 4.84642,5.73569 5.43954,5.72656 0.19139,-0.003 1.00069,-1.12768 1.7923,-2.5 l 1.44011,-2.49218 -1.46359,-1.42969 c -1.74469,-1.7009 -3.15687,-4.42419 -3.60027,-6.94531 -0.65587,-3.72915 0.73477,-7.91313 3.58462,-10.75782 l 1.4949,-1.48437 -1.44794,-2.45313 c -0.79721,-1.3482 -1.62713,-2.457 -1.8471,-2.46093 z m -11.48172,11.00781 c -0.9633,0.0352 -1.91614,0.41377 -2.69237,1.1875 -2.00987,2.00337 -1.64736,5.13021 0.77483,6.64844 1.21586,0.7621 3.46635,0.64626 4.72731,-0.25 0.50706,-0.3604 1.08552,-1.17918 1.36967,-1.92188 0.42186,-1.10264 0.44357,-1.46028 0.14089,-2.46875 -0.6246,-2.08092 -2.48131,-3.26251 -4.32033,-3.19531 z m 34.48431,5.39844 -0.21914,1.28125 c -0.3438,1.98869 -1.85107,4.75045 -3.48287,6.375 -3.52802,3.51233 -9.02028,4.5823 -13.61059,2.65625 -0.31683,-0.13294 -0.81591,0.51278 -1.90188,2.46093 l -1.47141,2.63282 1.08791,0.5 c 2.35906,1.08328 4.03098,1.35097 7.7171,1.25 1.9655,-0.0538 3.79469,-0.19399 4.06987,-0.3125 0.27517,-0.11852 0.50091,-0.41217 0.50091,-0.65625 0,-0.80589 1.40637,-2.86257 2.36365,-3.45313 1.32111,-0.81501 3.27853,-1.20069 4.58643,-0.90625 1.07501,0.24202 1.1022,0.22987 2.37147,-1.36719 0.70576,-0.88801 1.72249,-2.51849 2.25409,-3.61718 0.92244,-1.90647 2.06223,-6.31651 1.72186,-6.65625 -0.0888,-0.0886 -1.47469,-0.16332 -3.07588,-0.17188 l -2.91152,-0.0156 z m -1.72969,13.57031 c -0.6657,0.006 -1.3092,0.12563 -1.7923,0.375 -2.86148,1.47704 -2.99196,5.66848 -0.22699,7.35156 1.16072,0.70654 3.18099,0.68769 4.37512,-0.0391 2.51763,-1.53224 2.76259,-4.74097 0.52439,-6.82813 -0.60311,-0.56239 -1.77072,-0.86862 -2.88022,-0.85937 z"
|
||||||
|
id="path3059"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 5.3 KiB |
|
@ -0,0 +1,38 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<interface>
|
||||||
|
<!-- interface-requires about_mugshot_dialog 1.0 -->
|
||||||
|
<!-- interface-requires gtk+ 3.0 -->
|
||||||
|
<object class="AboutMugshotDialog" id="about_mugshot_dialog">
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="border_width">5</property>
|
||||||
|
<property name="icon">../media/mugshot.svg</property>
|
||||||
|
<property name="type_hint">normal</property>
|
||||||
|
<property name="program_name">Mugshot</property>
|
||||||
|
<property name="authors"></property>
|
||||||
|
<property name="logo">../media/mugshot.svg</property>
|
||||||
|
<child internal-child="vbox">
|
||||||
|
<object class="GtkBox" id="dialog-vbox1">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="orientation">vertical</property>
|
||||||
|
<property name="spacing">2</property>
|
||||||
|
<child internal-child="action_area">
|
||||||
|
<object class="GtkButtonBox" id="dialog-action_area1">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="layout_style">end</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
<property name="pack_type">end</property>
|
||||||
|
<property name="position">0</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<placeholder/>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</interface>
|
|
@ -0,0 +1,298 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<interface>
|
||||||
|
<!-- interface-requires gtk+ 3.0 -->
|
||||||
|
<!-- interface-requires mugshot_window 1.0 -->
|
||||||
|
<!-- interface-local-resource-path ../media -->
|
||||||
|
<object class="GtkImage" id="image2">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="stock">gtk-help</property>
|
||||||
|
</object>
|
||||||
|
<object class="MugshotWindow" id="mugshot_window">
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="title" translatable="yes">Mugshot</property>
|
||||||
|
<property name="icon">../media/mugshot.svg</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkVBox" id="vbox1">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="spacing">5</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkMenuBar" id="menubar1">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkMenuItem" id="mnu_file">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="use_action_appearance">False</property>
|
||||||
|
<property name="label" translatable="yes">_File</property>
|
||||||
|
<property name="use_underline">True</property>
|
||||||
|
<child type="submenu">
|
||||||
|
<object class="GtkMenu" id="menu1">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkImageMenuItem" id="mnu_new">
|
||||||
|
<property name="label">gtk-new</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="use_action_appearance">False</property>
|
||||||
|
<property name="use_underline">True</property>
|
||||||
|
<property name="use_stock">True</property>
|
||||||
|
<accelerator key="n" signal="activate" modifiers="GDK_CONTROL_MASK"/>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkImageMenuItem" id="mnu_open">
|
||||||
|
<property name="label">gtk-open</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="use_action_appearance">False</property>
|
||||||
|
<property name="use_underline">True</property>
|
||||||
|
<property name="use_stock">True</property>
|
||||||
|
<accelerator key="o" signal="activate" modifiers="GDK_CONTROL_MASK"/>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkSeparatorMenuItem" id="separatormenuitem3">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkImageMenuItem" id="mnu_save">
|
||||||
|
<property name="label">gtk-save</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="use_action_appearance">False</property>
|
||||||
|
<property name="use_underline">True</property>
|
||||||
|
<property name="use_stock">True</property>
|
||||||
|
<accelerator key="s" signal="activate" modifiers="GDK_CONTROL_MASK"/>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkImageMenuItem" id="mnu_save_as">
|
||||||
|
<property name="label">gtk-save-as</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="use_action_appearance">False</property>
|
||||||
|
<property name="use_underline">True</property>
|
||||||
|
<property name="use_stock">True</property>
|
||||||
|
<accelerator key="s" signal="activate" modifiers="GDK_SHIFT_MASK | GDK_CONTROL_MASK"/>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkSeparatorMenuItem" id="separatormenuitem1">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkImageMenuItem" id="mnu_close">
|
||||||
|
<property name="label">gtk-close</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="use_action_appearance">False</property>
|
||||||
|
<property name="use_underline">True</property>
|
||||||
|
<property name="use_stock">True</property>
|
||||||
|
<accelerator key="w" signal="activate" modifiers="GDK_CONTROL_MASK"/>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkMenuItem" id="mnu_edit">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="use_action_appearance">False</property>
|
||||||
|
<property name="label" translatable="yes">_Edit</property>
|
||||||
|
<property name="use_underline">True</property>
|
||||||
|
<child type="submenu">
|
||||||
|
<object class="GtkMenu" id="menu2">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkImageMenuItem" id="mnu_cut">
|
||||||
|
<property name="label">gtk-cut</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="use_action_appearance">False</property>
|
||||||
|
<property name="use_underline">True</property>
|
||||||
|
<property name="use_stock">True</property>
|
||||||
|
<accelerator key="x" signal="activate" modifiers="GDK_CONTROL_MASK"/>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkImageMenuItem" id="mnu_copy">
|
||||||
|
<property name="label">gtk-copy</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="use_action_appearance">False</property>
|
||||||
|
<property name="use_underline">True</property>
|
||||||
|
<property name="use_stock">True</property>
|
||||||
|
<accelerator key="c" signal="activate" modifiers="GDK_CONTROL_MASK"/>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkImageMenuItem" id="mnu_paste">
|
||||||
|
<property name="label">gtk-paste</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="use_action_appearance">False</property>
|
||||||
|
<property name="use_underline">True</property>
|
||||||
|
<property name="use_stock">True</property>
|
||||||
|
<accelerator key="v" signal="activate" modifiers="GDK_CONTROL_MASK"/>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkImageMenuItem" id="mnu_delete">
|
||||||
|
<property name="label">gtk-delete</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="use_action_appearance">False</property>
|
||||||
|
<property name="use_underline">True</property>
|
||||||
|
<property name="use_stock">True</property>
|
||||||
|
<accelerator key="Delete" signal="activate"/>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkSeparatorMenuItem" id="separatormenuitem2">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkImageMenuItem" id="mnu_preferences">
|
||||||
|
<property name="label">gtk-preferences</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="use_action_appearance">False</property>
|
||||||
|
<property name="use_underline">True</property>
|
||||||
|
<property name="use_stock">True</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkMenuItem" id="mnu_view">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="use_action_appearance">False</property>
|
||||||
|
<property name="label" translatable="yes">_View</property>
|
||||||
|
<property name="use_underline">True</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkMenuItem" id="mnu_help">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="use_action_appearance">False</property>
|
||||||
|
<property name="label" translatable="yes">_Help</property>
|
||||||
|
<property name="use_underline">True</property>
|
||||||
|
<child type="submenu">
|
||||||
|
<object class="GtkMenu" id="helpMenu">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkImageMenuItem" id="mnu_contents">
|
||||||
|
<property name="label" translatable="yes">Contents</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="use_action_appearance">False</property>
|
||||||
|
<property name="image">image2</property>
|
||||||
|
<property name="use_stock">False</property>
|
||||||
|
<accelerator key="F1" signal="activate"/>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkImageMenuItem" id="mnu_about">
|
||||||
|
<property name="label">gtk-about</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="use_action_appearance">False</property>
|
||||||
|
<property name="use_underline">True</property>
|
||||||
|
<property name="use_stock">True</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
<property name="position">0</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel" id="label1">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="xpad">30</property>
|
||||||
|
<property name="ypad">5</property>
|
||||||
|
<property name="label" translatable="yes">Your application has been created!
|
||||||
|
|
||||||
|
To start changing this user interface, run 'quickly design', which will open Glade so you can edit the default windows and dialogs.
|
||||||
|
|
||||||
|
To change the behavior and edit the python code, run 'quickly edit', which will bring up a text editor.</property>
|
||||||
|
<property name="wrap">True</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">True</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
<property name="position">1</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkImage" id="image1">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="xpad">5</property>
|
||||||
|
<property name="ypad">5</property>
|
||||||
|
<property name="pixbuf">../media/background.png</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">True</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
<property name="padding">15</property>
|
||||||
|
<property name="position">2</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkStatusbar" id="statusbar1">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="spacing">2</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel" id="label2">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="xalign">0</property>
|
||||||
|
<property name="xpad">5</property>
|
||||||
|
<property name="ypad">5</property>
|
||||||
|
<property name="label" translatable="yes">Status Area</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">True</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
<property name="position">0</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
<property name="pack_type">end</property>
|
||||||
|
<property name="position">3</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</interface>
|
|
@ -0,0 +1,112 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<interface>
|
||||||
|
<!-- interface-requires gtk+ 3.0 -->
|
||||||
|
<!-- interface-requires preferences_mugshot_dialog 1.0 -->
|
||||||
|
<object class="PreferencesMugshotDialog" id="preferences_mugshot_dialog">
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="title" translatable="yes">Mugshot Preferences</property>
|
||||||
|
<property name="icon">../media/mugshot.svg</property>
|
||||||
|
<property name="type_hint">normal</property>
|
||||||
|
<child internal-child="vbox">
|
||||||
|
<object class="GtkBox" id="dialog-vbox1">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="orientation">vertical</property>
|
||||||
|
<property name="spacing">12</property>
|
||||||
|
<child internal-child="action_area">
|
||||||
|
<object class="GtkButtonBox" id="dialog-action_area1">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="layout_style">end</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkButton" id="btn_help">
|
||||||
|
<property name="label">gtk-help</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="receives_default">True</property>
|
||||||
|
<property name="use_action_appearance">False</property>
|
||||||
|
<property name="use_stock">True</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">False</property>
|
||||||
|
<property name="position">0</property>
|
||||||
|
<property name="secondary">True</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkButton" id="btn_close">
|
||||||
|
<property name="label">gtk-close</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="receives_default">True</property>
|
||||||
|
<property name="use_action_appearance">False</property>
|
||||||
|
<property name="use_stock">True</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">False</property>
|
||||||
|
<property name="position">1</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
<property name="pack_type">end</property>
|
||||||
|
<property name="position">0</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkGrid" id="table1">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="row_spacing">6</property>
|
||||||
|
<property name="column_spacing">6</property>
|
||||||
|
<property name="n_rows">1</property>
|
||||||
|
<property name="n_columns">2</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkEntry" id="example_entry">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="hexpand">True</property>
|
||||||
|
<property name="invisible_char">•</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left_attach">1</property>
|
||||||
|
<property name="top_attach">0</property>
|
||||||
|
<property name="width">1</property>
|
||||||
|
<property name="height">1</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel" id="example_entry_label">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="xalign">0</property>
|
||||||
|
<property name="label" translatable="yes">_Example entry:</property>
|
||||||
|
<property name="use_underline">True</property>
|
||||||
|
<property name="mnemonic_widget">example_entry</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left_attach">0</property>
|
||||||
|
<property name="top_attach">0</property>
|
||||||
|
<property name="width">1</property>
|
||||||
|
<property name="height">1</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
<property name="position">1</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<action-widgets>
|
||||||
|
<action-widget response="-11">btn_help</action-widget>
|
||||||
|
<action-widget response="-7">btn_close</action-widget>
|
||||||
|
</action-widgets>
|
||||||
|
</object>
|
||||||
|
</interface>
|
|
@ -0,0 +1,9 @@
|
||||||
|
<glade-catalog name="about_mugshot_dialog" domain="glade-3"
|
||||||
|
depends="gtk+" version="1.0">
|
||||||
|
<glade-widget-classes>
|
||||||
|
<glade-widget-class title="About Mugshot Dialog" name="AboutMugshotDialog"
|
||||||
|
generic-name="AboutMugshotDialog" parent="GtkAboutDialog"
|
||||||
|
icon-name="widget-gtk-about-dialog"/>
|
||||||
|
</glade-widget-classes>
|
||||||
|
|
||||||
|
</glade-catalog>
|
|
@ -0,0 +1,8 @@
|
||||||
|
<glade-catalog name="mugshot_window" domain="glade-3"
|
||||||
|
depends="gtk+" version="1.0">
|
||||||
|
<glade-widget-classes>
|
||||||
|
<glade-widget-class title="Mugshot Window" name="MugshotWindow"
|
||||||
|
generic-name="MugshotWindow" parent="GtkWindow"
|
||||||
|
icon-name="widget-gtk-window"/>
|
||||||
|
</glade-widget-classes>
|
||||||
|
</glade-catalog>
|
|
@ -0,0 +1,9 @@
|
||||||
|
<glade-catalog name="preferences_mugshot_dialog" domain="glade-3"
|
||||||
|
depends="gtk+" version="1.0">
|
||||||
|
<glade-widget-classes>
|
||||||
|
<glade-widget-class title="Mugshot Preferences Dialog" name="PreferencesMugshotDialog"
|
||||||
|
generic-name="PreferenceMugshotDialog" parent="GtkDialog"
|
||||||
|
icon-name="widget-gtk-dialog"/>
|
||||||
|
</glade-widget-classes>
|
||||||
|
|
||||||
|
</glade-catalog>
|
Binary file not shown.
After Width: | Height: | Size: 669 B |
|
@ -0,0 +1,44 @@
|
||||||
|
<page xmlns="http://projectmallard.org/1.0/"
|
||||||
|
type="guide"
|
||||||
|
id="index">
|
||||||
|
|
||||||
|
<info>
|
||||||
|
<!-- This shows in the title bar so does not show [icon] -->
|
||||||
|
<title type="text">Mugshot</title>
|
||||||
|
<desc>The <app>Mugshot</app> help.</desc>
|
||||||
|
<credit type="author">
|
||||||
|
<name>Your Name</name>
|
||||||
|
<email>Your E-mail</email>
|
||||||
|
<years>2010</years>
|
||||||
|
</credit>
|
||||||
|
<license href="http://creativecommons.org/licenses/by-sa/3.0/">
|
||||||
|
<p>Creative Commons Attribution-Share Alike 3.0 Unported License</p>
|
||||||
|
</license>
|
||||||
|
</info>
|
||||||
|
|
||||||
|
<title>
|
||||||
|
<!-- This shows on the page in title font -->
|
||||||
|
<!-- the icon only shows when installed -->
|
||||||
|
<media type="image" mime="image/png" src="figures/icon.png">[icon]</media>
|
||||||
|
<app>Mugshot</app> Help
|
||||||
|
</title>
|
||||||
|
|
||||||
|
<p>This is an example guide page. It's main function is to link together the help topics.</p>
|
||||||
|
|
||||||
|
<!-- This is the visible index -->
|
||||||
|
<section id="contents" style="2column">
|
||||||
|
<!-- other pages needs to have a link to index#contents for this to work -->
|
||||||
|
<title>Contents</title>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<note>
|
||||||
|
<!-- delete this note -->
|
||||||
|
<p>
|
||||||
|
Your script or application looks better if it has help files similar to other applications in ubuntu.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Some people think that help files are only for apps that are difficult to use.
|
||||||
|
</p>
|
||||||
|
</note>
|
||||||
|
|
||||||
|
</page>
|
|
@ -0,0 +1,18 @@
|
||||||
|
<page xmlns="http://projectmallard.org/1.0/"
|
||||||
|
type="topic"
|
||||||
|
id="preferences">
|
||||||
|
|
||||||
|
<info>
|
||||||
|
<link type="guide" xref="index#contents"/>
|
||||||
|
<credit type="author">
|
||||||
|
<name>Your Name</name>
|
||||||
|
<email>Your E-mail</email>
|
||||||
|
<years>2010</years>
|
||||||
|
</credit>
|
||||||
|
<desc>Optional short description of Preferences for contents page</desc>
|
||||||
|
</info>
|
||||||
|
|
||||||
|
<title>Preferences</title>
|
||||||
|
<p>This is the preferences page.</p>
|
||||||
|
|
||||||
|
</page>
|
|
@ -0,0 +1,18 @@
|
||||||
|
<page xmlns="http://projectmallard.org/1.0/"
|
||||||
|
type="topic"
|
||||||
|
id="topic1">
|
||||||
|
|
||||||
|
<info>
|
||||||
|
<link type="guide" xref="index#contents"/>
|
||||||
|
<credit type="author">
|
||||||
|
<name>Your Name</name>
|
||||||
|
<email>Your E-mail</email>
|
||||||
|
<years>2010</years>
|
||||||
|
</credit>
|
||||||
|
<desc>Optional short description of Topic 1 for contents page</desc>
|
||||||
|
</info>
|
||||||
|
|
||||||
|
<title>Topic 1</title>
|
||||||
|
<p>This is an example topic page. It's main function is to describe one topic.</p>
|
||||||
|
|
||||||
|
</page>
|
|
@ -0,0 +1,8 @@
|
||||||
|
[Desktop Entry]
|
||||||
|
_Name=Mugshot
|
||||||
|
_Comment=Mugshot application
|
||||||
|
Categories=GNOME;Utility;
|
||||||
|
Exec=mugshot
|
||||||
|
Icon=mugshot
|
||||||
|
Terminal=false
|
||||||
|
Type=Application
|
|
@ -0,0 +1,22 @@
|
||||||
|
# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
|
||||||
|
### BEGIN LICENSE
|
||||||
|
# This file is in the public domain
|
||||||
|
### END LICENSE
|
||||||
|
|
||||||
|
from locale import gettext as _
|
||||||
|
|
||||||
|
import logging
|
||||||
|
logger = logging.getLogger('mugshot')
|
||||||
|
|
||||||
|
from mugshot_lib.AboutDialog import AboutDialog
|
||||||
|
|
||||||
|
# See mugshot_lib.AboutDialog.py for more details about how this class works.
|
||||||
|
class AboutMugshotDialog(AboutDialog):
|
||||||
|
__gtype_name__ = "AboutMugshotDialog"
|
||||||
|
|
||||||
|
def finish_initializing(self, builder): # pylint: disable=E1002
|
||||||
|
"""Set up the about dialog"""
|
||||||
|
super(AboutMugshotDialog, self).finish_initializing(builder)
|
||||||
|
|
||||||
|
# Code for other initialization actions should be added here.
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
|
||||||
|
### BEGIN LICENSE
|
||||||
|
# This file is in the public domain
|
||||||
|
### END LICENSE
|
||||||
|
|
||||||
|
from locale import gettext as _
|
||||||
|
|
||||||
|
from gi.repository import Gtk # pylint: disable=E0611
|
||||||
|
import logging
|
||||||
|
logger = logging.getLogger('mugshot')
|
||||||
|
|
||||||
|
from mugshot_lib import Window
|
||||||
|
from mugshot.AboutMugshotDialog import AboutMugshotDialog
|
||||||
|
from mugshot.PreferencesMugshotDialog import PreferencesMugshotDialog
|
||||||
|
|
||||||
|
# See mugshot_lib.Window.py for more details about how this class works
|
||||||
|
class MugshotWindow(Window):
|
||||||
|
__gtype_name__ = "MugshotWindow"
|
||||||
|
|
||||||
|
def finish_initializing(self, builder): # pylint: disable=E1002
|
||||||
|
"""Set up the main window"""
|
||||||
|
super(MugshotWindow, self).finish_initializing(builder)
|
||||||
|
|
||||||
|
self.AboutDialog = AboutMugshotDialog
|
||||||
|
self.PreferencesDialog = PreferencesMugshotDialog
|
||||||
|
|
||||||
|
# Code for other initialization actions should be added here.
|
||||||
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
|
||||||
|
### BEGIN LICENSE
|
||||||
|
# This file is in the public domain
|
||||||
|
### END LICENSE
|
||||||
|
|
||||||
|
# This is your preferences dialog.
|
||||||
|
#
|
||||||
|
# Define your preferences in
|
||||||
|
# data/glib-2.0/schemas/net.launchpad.mugshot.gschema.xml
|
||||||
|
# See http://developer.gnome.org/gio/stable/GSettings.html for more info.
|
||||||
|
|
||||||
|
from gi.repository import Gio # pylint: disable=E0611
|
||||||
|
|
||||||
|
from locale import gettext as _
|
||||||
|
|
||||||
|
import logging
|
||||||
|
logger = logging.getLogger('mugshot')
|
||||||
|
|
||||||
|
from mugshot_lib.PreferencesDialog import PreferencesDialog
|
||||||
|
|
||||||
|
class PreferencesMugshotDialog(PreferencesDialog):
|
||||||
|
__gtype_name__ = "PreferencesMugshotDialog"
|
||||||
|
|
||||||
|
def finish_initializing(self, builder): # pylint: disable=E1002
|
||||||
|
"""Set up the preferences dialog"""
|
||||||
|
super(PreferencesMugshotDialog, self).finish_initializing(builder)
|
||||||
|
|
||||||
|
# Bind each preference widget to gsettings
|
||||||
|
settings = Gio.Settings("net.launchpad.mugshot")
|
||||||
|
widget = self.builder.get_object('example_entry')
|
||||||
|
settings.bind("example", widget, "text", Gio.SettingsBindFlags.DEFAULT)
|
||||||
|
|
||||||
|
# Code for other initialization actions should be added here.
|
|
@ -0,0 +1,33 @@
|
||||||
|
# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
|
||||||
|
### BEGIN LICENSE
|
||||||
|
# This file is in the public domain
|
||||||
|
### END LICENSE
|
||||||
|
|
||||||
|
import optparse
|
||||||
|
|
||||||
|
from locale import gettext as _
|
||||||
|
|
||||||
|
from gi.repository import Gtk # pylint: disable=E0611
|
||||||
|
|
||||||
|
from mugshot import MugshotWindow
|
||||||
|
|
||||||
|
from mugshot_lib import set_up_logging, get_version
|
||||||
|
|
||||||
|
def parse_options():
|
||||||
|
"""Support for command line options"""
|
||||||
|
parser = optparse.OptionParser(version="%%prog %s" % get_version())
|
||||||
|
parser.add_option(
|
||||||
|
"-v", "--verbose", action="count", dest="verbose",
|
||||||
|
help=_("Show debug messages (-vv debugs mugshot_lib also)"))
|
||||||
|
(options, args) = parser.parse_args()
|
||||||
|
|
||||||
|
set_up_logging(options)
|
||||||
|
|
||||||
|
def main():
|
||||||
|
'constructor for your class instances'
|
||||||
|
parse_options()
|
||||||
|
|
||||||
|
# Run the application.
|
||||||
|
window = MugshotWindow.MugshotWindow()
|
||||||
|
window.show()
|
||||||
|
Gtk.main()
|
|
@ -0,0 +1,39 @@
|
||||||
|
# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
|
||||||
|
### BEGIN LICENSE
|
||||||
|
# This file is in the public domain
|
||||||
|
### END LICENSE
|
||||||
|
|
||||||
|
### DO NOT EDIT THIS FILE ###
|
||||||
|
|
||||||
|
from gi.repository import Gtk # pylint: disable=E0611
|
||||||
|
|
||||||
|
from . helpers import get_builder
|
||||||
|
|
||||||
|
class AboutDialog(Gtk.AboutDialog):
|
||||||
|
__gtype_name__ = "AboutDialog"
|
||||||
|
|
||||||
|
def __new__(cls):
|
||||||
|
"""Special static method that's automatically called by Python when
|
||||||
|
constructing a new instance of this class.
|
||||||
|
|
||||||
|
Returns a fully instantiated AboutDialog object.
|
||||||
|
"""
|
||||||
|
builder = get_builder('AboutMugshotDialog')
|
||||||
|
new_object = builder.get_object("about_mugshot_dialog")
|
||||||
|
new_object.finish_initializing(builder)
|
||||||
|
return new_object
|
||||||
|
|
||||||
|
def finish_initializing(self, builder):
|
||||||
|
"""Called while initializing this instance in __new__
|
||||||
|
|
||||||
|
finish_initalizing should be called after parsing the ui definition
|
||||||
|
and creating a AboutDialog object with it in order
|
||||||
|
to finish initializing the start of the new AboutMugshotDialog
|
||||||
|
instance.
|
||||||
|
|
||||||
|
Put your initialization code in here and leave __init__ undefined.
|
||||||
|
"""
|
||||||
|
# Get a reference to the builder and set up the signals.
|
||||||
|
self.builder = builder
|
||||||
|
self.ui = builder.get_ui(self)
|
||||||
|
|
|
@ -0,0 +1,314 @@
|
||||||
|
# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
|
||||||
|
### BEGIN LICENSE
|
||||||
|
# This file is in the public domain
|
||||||
|
### END LICENSE
|
||||||
|
|
||||||
|
### DO NOT EDIT THIS FILE ###
|
||||||
|
|
||||||
|
'''Enhances builder connections, provides object to access glade objects'''
|
||||||
|
|
||||||
|
from gi.repository import GObject, Gtk # pylint: disable=E0611
|
||||||
|
|
||||||
|
import inspect
|
||||||
|
import functools
|
||||||
|
import logging
|
||||||
|
logger = logging.getLogger('mugshot_lib')
|
||||||
|
|
||||||
|
from xml.etree.cElementTree import ElementTree
|
||||||
|
|
||||||
|
# this module is big so uses some conventional prefixes and postfixes
|
||||||
|
# *s list, except self.widgets is a dictionary
|
||||||
|
# *_dict dictionary
|
||||||
|
# *name string
|
||||||
|
# ele_* element in a ElementTree
|
||||||
|
|
||||||
|
|
||||||
|
# pylint: disable=R0904
|
||||||
|
# the many public methods is a feature of Gtk.Builder
|
||||||
|
class Builder(Gtk.Builder):
|
||||||
|
''' extra features
|
||||||
|
connects glade defined handler to default_handler if necessary
|
||||||
|
auto connects widget to handler with matching name or alias
|
||||||
|
auto connects several widgets to a handler via multiple aliases
|
||||||
|
allow handlers to lookup widget name
|
||||||
|
logs every connection made, and any on_* not made
|
||||||
|
'''
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
Gtk.Builder.__init__(self)
|
||||||
|
self.widgets = {}
|
||||||
|
self.glade_handler_dict = {}
|
||||||
|
self.connections = []
|
||||||
|
self._reverse_widget_dict = {}
|
||||||
|
|
||||||
|
# pylint: disable=R0201
|
||||||
|
# this is a method so that a subclass of Builder can redefine it
|
||||||
|
def default_handler(self,
|
||||||
|
handler_name, filename, *args, **kwargs):
|
||||||
|
'''helps the apprentice guru
|
||||||
|
|
||||||
|
glade defined handlers that do not exist come here instead.
|
||||||
|
An apprentice guru might wonder which signal does what he wants,
|
||||||
|
now he can define any likely candidates in glade and notice which
|
||||||
|
ones get triggered when he plays with the project.
|
||||||
|
this method does not appear in Gtk.Builder'''
|
||||||
|
logger.debug('''tried to call non-existent function:%s()
|
||||||
|
expected in %s
|
||||||
|
args:%s
|
||||||
|
kwargs:%s''', handler_name, filename, args, kwargs)
|
||||||
|
# pylint: enable=R0201
|
||||||
|
|
||||||
|
def get_name(self, widget):
|
||||||
|
''' allows a handler to get the name (id) of a widget
|
||||||
|
|
||||||
|
this method does not appear in Gtk.Builder'''
|
||||||
|
return self._reverse_widget_dict.get(widget)
|
||||||
|
|
||||||
|
def add_from_file(self, filename):
|
||||||
|
'''parses xml file and stores wanted details'''
|
||||||
|
Gtk.Builder.add_from_file(self, filename)
|
||||||
|
|
||||||
|
# extract data for the extra interfaces
|
||||||
|
tree = ElementTree()
|
||||||
|
tree.parse(filename)
|
||||||
|
|
||||||
|
ele_widgets = tree.getiterator("object")
|
||||||
|
for ele_widget in ele_widgets:
|
||||||
|
name = ele_widget.attrib['id']
|
||||||
|
widget = self.get_object(name)
|
||||||
|
|
||||||
|
# populate indexes - a dictionary of widgets
|
||||||
|
self.widgets[name] = widget
|
||||||
|
|
||||||
|
# populate a reversed dictionary
|
||||||
|
self._reverse_widget_dict[widget] = name
|
||||||
|
|
||||||
|
# populate connections list
|
||||||
|
ele_signals = ele_widget.findall("signal")
|
||||||
|
|
||||||
|
connections = [
|
||||||
|
(name,
|
||||||
|
ele_signal.attrib['name'],
|
||||||
|
ele_signal.attrib['handler']) for ele_signal in ele_signals]
|
||||||
|
|
||||||
|
if connections:
|
||||||
|
self.connections.extend(connections)
|
||||||
|
|
||||||
|
ele_signals = tree.getiterator("signal")
|
||||||
|
for ele_signal in ele_signals:
|
||||||
|
self.glade_handler_dict.update(
|
||||||
|
{ele_signal.attrib["handler"]: None})
|
||||||
|
|
||||||
|
def connect_signals(self, callback_obj):
|
||||||
|
'''connect the handlers defined in glade
|
||||||
|
|
||||||
|
reports successful and failed connections
|
||||||
|
and logs call to missing handlers'''
|
||||||
|
filename = inspect.getfile(callback_obj.__class__)
|
||||||
|
callback_handler_dict = dict_from_callback_obj(callback_obj)
|
||||||
|
connection_dict = {}
|
||||||
|
connection_dict.update(self.glade_handler_dict)
|
||||||
|
connection_dict.update(callback_handler_dict)
|
||||||
|
for item in connection_dict.items():
|
||||||
|
if item[1] is None:
|
||||||
|
# the handler is missing so reroute to default_handler
|
||||||
|
handler = functools.partial(
|
||||||
|
self.default_handler, item[0], filename)
|
||||||
|
|
||||||
|
connection_dict[item[0]] = handler
|
||||||
|
|
||||||
|
# replace the run time warning
|
||||||
|
logger.warn("expected handler '%s' in %s",
|
||||||
|
item[0], filename)
|
||||||
|
|
||||||
|
# connect glade define handlers
|
||||||
|
Gtk.Builder.connect_signals(self, connection_dict)
|
||||||
|
|
||||||
|
# let's tell the user how we applied the glade design
|
||||||
|
for connection in self.connections:
|
||||||
|
widget_name, signal_name, handler_name = connection
|
||||||
|
logger.debug("connect builder by design '%s', '%s', '%s'",
|
||||||
|
widget_name, signal_name, handler_name)
|
||||||
|
|
||||||
|
def get_ui(self, callback_obj=None, by_name=True):
|
||||||
|
'''Creates the ui object with widgets as attributes
|
||||||
|
|
||||||
|
connects signals by 2 methods
|
||||||
|
this method does not appear in Gtk.Builder'''
|
||||||
|
|
||||||
|
result = UiFactory(self.widgets)
|
||||||
|
|
||||||
|
# Hook up any signals the user defined in glade
|
||||||
|
if callback_obj is not None:
|
||||||
|
# connect glade define handlers
|
||||||
|
self.connect_signals(callback_obj)
|
||||||
|
|
||||||
|
if by_name:
|
||||||
|
auto_connect_by_name(callback_obj, self)
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
# pylint: disable=R0903
|
||||||
|
# this class deliberately does not provide any public interfaces
|
||||||
|
# apart from the glade widgets
|
||||||
|
class UiFactory():
|
||||||
|
''' provides an object with attributes as glade widgets'''
|
||||||
|
def __init__(self, widget_dict):
|
||||||
|
self._widget_dict = widget_dict
|
||||||
|
for (widget_name, widget) in widget_dict.items():
|
||||||
|
setattr(self, widget_name, widget)
|
||||||
|
|
||||||
|
# Mangle any non-usable names (like with spaces or dashes)
|
||||||
|
# into pythonic ones
|
||||||
|
cannot_message = """cannot bind ui.%s, name already exists
|
||||||
|
consider using a pythonic name instead of design name '%s'"""
|
||||||
|
consider_message = """consider using a pythonic name instead of design name '%s'"""
|
||||||
|
|
||||||
|
for (widget_name, widget) in widget_dict.items():
|
||||||
|
pyname = make_pyname(widget_name)
|
||||||
|
if pyname != widget_name:
|
||||||
|
if hasattr(self, pyname):
|
||||||
|
logger.debug(cannot_message, pyname, widget_name)
|
||||||
|
else:
|
||||||
|
logger.debug(consider_message, widget_name)
|
||||||
|
setattr(self, pyname, widget)
|
||||||
|
|
||||||
|
def iterator():
|
||||||
|
'''Support 'for o in self' '''
|
||||||
|
return iter(widget_dict.values())
|
||||||
|
setattr(self, '__iter__', iterator)
|
||||||
|
|
||||||
|
def __getitem__(self, name):
|
||||||
|
'access as dictionary where name might be non-pythonic'
|
||||||
|
return self._widget_dict[name]
|
||||||
|
# pylint: enable=R0903
|
||||||
|
|
||||||
|
|
||||||
|
def make_pyname(name):
|
||||||
|
''' mangles non-pythonic names into pythonic ones'''
|
||||||
|
pyname = ''
|
||||||
|
for character in name:
|
||||||
|
if (character.isalpha() or character == '_' or
|
||||||
|
(pyname and character.isdigit())):
|
||||||
|
pyname += character
|
||||||
|
else:
|
||||||
|
pyname += '_'
|
||||||
|
return pyname
|
||||||
|
|
||||||
|
|
||||||
|
# Until bug https://bugzilla.gnome.org/show_bug.cgi?id=652127 is fixed, we
|
||||||
|
# need to reimplement inspect.getmembers. GObject introspection doesn't
|
||||||
|
# play nice with it.
|
||||||
|
def getmembers(obj, check):
|
||||||
|
members = []
|
||||||
|
for k in dir(obj):
|
||||||
|
try:
|
||||||
|
attr = getattr(obj, k)
|
||||||
|
except:
|
||||||
|
continue
|
||||||
|
if check(attr):
|
||||||
|
members.append((k, attr))
|
||||||
|
members.sort()
|
||||||
|
return members
|
||||||
|
|
||||||
|
|
||||||
|
def dict_from_callback_obj(callback_obj):
|
||||||
|
'''a dictionary interface to callback_obj'''
|
||||||
|
methods = getmembers(callback_obj, inspect.ismethod)
|
||||||
|
|
||||||
|
aliased_methods = [x[1] for x in methods if hasattr(x[1], 'aliases')]
|
||||||
|
|
||||||
|
# a method may have several aliases
|
||||||
|
#~ @alias('on_btn_foo_clicked')
|
||||||
|
#~ @alias('on_tool_foo_activate')
|
||||||
|
#~ on_menu_foo_activate():
|
||||||
|
#~ pass
|
||||||
|
alias_groups = [(x.aliases, x) for x in aliased_methods]
|
||||||
|
|
||||||
|
aliases = []
|
||||||
|
for item in alias_groups:
|
||||||
|
for alias in item[0]:
|
||||||
|
aliases.append((alias, item[1]))
|
||||||
|
|
||||||
|
dict_methods = dict(methods)
|
||||||
|
dict_aliases = dict(aliases)
|
||||||
|
|
||||||
|
results = {}
|
||||||
|
results.update(dict_methods)
|
||||||
|
results.update(dict_aliases)
|
||||||
|
|
||||||
|
return results
|
||||||
|
|
||||||
|
|
||||||
|
def auto_connect_by_name(callback_obj, builder):
|
||||||
|
'''finds handlers like on_<widget_name>_<signal> and connects them
|
||||||
|
|
||||||
|
i.e. find widget,signal pair in builder and call
|
||||||
|
widget.connect(signal, on_<widget_name>_<signal>)'''
|
||||||
|
|
||||||
|
callback_handler_dict = dict_from_callback_obj(callback_obj)
|
||||||
|
|
||||||
|
for item in builder.widgets.items():
|
||||||
|
(widget_name, widget) = item
|
||||||
|
signal_ids = []
|
||||||
|
try:
|
||||||
|
widget_type = type(widget)
|
||||||
|
while widget_type:
|
||||||
|
signal_ids.extend(GObject.signal_list_ids(widget_type))
|
||||||
|
widget_type = GObject.type_parent(widget_type)
|
||||||
|
except RuntimeError: # pylint wants a specific error
|
||||||
|
pass
|
||||||
|
signal_names = [GObject.signal_name(sid) for sid in signal_ids]
|
||||||
|
|
||||||
|
# Now, automatically find any the user didn't specify in glade
|
||||||
|
for sig in signal_names:
|
||||||
|
# using convention suggested by glade
|
||||||
|
sig = sig.replace("-", "_")
|
||||||
|
handler_names = ["on_%s_%s" % (widget_name, sig)]
|
||||||
|
|
||||||
|
# Using the convention that the top level window is not
|
||||||
|
# specified in the handler name. That is use
|
||||||
|
# on_destroy() instead of on_windowname_destroy()
|
||||||
|
if widget is callback_obj:
|
||||||
|
handler_names.append("on_%s" % sig)
|
||||||
|
|
||||||
|
do_connect(item, sig, handler_names,
|
||||||
|
callback_handler_dict, builder.connections)
|
||||||
|
|
||||||
|
log_unconnected_functions(callback_handler_dict, builder.connections)
|
||||||
|
|
||||||
|
|
||||||
|
def do_connect(item, signal_name, handler_names,
|
||||||
|
callback_handler_dict, connections):
|
||||||
|
'''connect this signal to an unused handler'''
|
||||||
|
widget_name, widget = item
|
||||||
|
|
||||||
|
for handler_name in handler_names:
|
||||||
|
target = handler_name in callback_handler_dict.keys()
|
||||||
|
connection = (widget_name, signal_name, handler_name)
|
||||||
|
duplicate = connection in connections
|
||||||
|
if target and not duplicate:
|
||||||
|
widget.connect(signal_name, callback_handler_dict[handler_name])
|
||||||
|
connections.append(connection)
|
||||||
|
|
||||||
|
logger.debug("connect builder by name '%s','%s', '%s'",
|
||||||
|
widget_name, signal_name, handler_name)
|
||||||
|
|
||||||
|
|
||||||
|
def log_unconnected_functions(callback_handler_dict, connections):
|
||||||
|
'''log functions like on_* that we could not connect'''
|
||||||
|
|
||||||
|
connected_functions = [x[2] for x in connections]
|
||||||
|
|
||||||
|
handler_names = callback_handler_dict.keys()
|
||||||
|
unconnected = [x for x in handler_names if x.startswith('on_')]
|
||||||
|
|
||||||
|
for handler_name in connected_functions:
|
||||||
|
try:
|
||||||
|
unconnected.remove(handler_name)
|
||||||
|
except ValueError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
for handler_name in unconnected:
|
||||||
|
logger.debug("Not connected to builder '%s'", handler_name)
|
|
@ -0,0 +1,53 @@
|
||||||
|
# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
|
||||||
|
### BEGIN LICENSE
|
||||||
|
# This file is in the public domain
|
||||||
|
### END LICENSE
|
||||||
|
|
||||||
|
### DO NOT EDIT THIS FILE ###
|
||||||
|
|
||||||
|
"""this dialog adjusts values in gsettings
|
||||||
|
"""
|
||||||
|
|
||||||
|
from gi.repository import Gtk # pylint: disable=E0611
|
||||||
|
import logging
|
||||||
|
logger = logging.getLogger('mugshot_lib')
|
||||||
|
|
||||||
|
from . helpers import get_builder, show_uri, get_help_uri
|
||||||
|
|
||||||
|
class PreferencesDialog(Gtk.Dialog):
|
||||||
|
__gtype_name__ = "PreferencesDialog"
|
||||||
|
|
||||||
|
def __new__(cls):
|
||||||
|
"""Special static method that's automatically called by Python when
|
||||||
|
constructing a new instance of this class.
|
||||||
|
|
||||||
|
Returns a fully instantiated PreferencesDialog object.
|
||||||
|
"""
|
||||||
|
builder = get_builder('PreferencesMugshotDialog')
|
||||||
|
new_object = builder.get_object("preferences_mugshot_dialog")
|
||||||
|
new_object.finish_initializing(builder)
|
||||||
|
return new_object
|
||||||
|
|
||||||
|
def finish_initializing(self, builder):
|
||||||
|
"""Called while initializing this instance in __new__
|
||||||
|
|
||||||
|
finish_initalizing should be called after parsing the ui definition
|
||||||
|
and creating a PreferencesDialog object with it in order to
|
||||||
|
finish initializing the start of the new PerferencesMugshotDialog
|
||||||
|
instance.
|
||||||
|
|
||||||
|
Put your initialization code in here and leave __init__ undefined.
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Get a reference to the builder and set up the signals.
|
||||||
|
self.builder = builder
|
||||||
|
self.ui = builder.get_ui(self, True)
|
||||||
|
|
||||||
|
# code for other initialization actions should be added here
|
||||||
|
|
||||||
|
def on_btn_close_clicked(self, widget, data=None):
|
||||||
|
self.destroy()
|
||||||
|
|
||||||
|
def on_btn_help_clicked(self, widget, data=None):
|
||||||
|
show_uri(self, "ghelp:%s" % get_help_uri('preferences'))
|
||||||
|
|
|
@ -0,0 +1,118 @@
|
||||||
|
# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
|
||||||
|
### BEGIN LICENSE
|
||||||
|
# This file is in the public domain
|
||||||
|
### END LICENSE
|
||||||
|
|
||||||
|
### DO NOT EDIT THIS FILE ###
|
||||||
|
|
||||||
|
from gi.repository import Gio, Gtk # pylint: disable=E0611
|
||||||
|
import logging
|
||||||
|
logger = logging.getLogger('mugshot_lib')
|
||||||
|
|
||||||
|
from . helpers import get_builder, show_uri, get_help_uri
|
||||||
|
|
||||||
|
# This class is meant to be subclassed by MugshotWindow. It provides
|
||||||
|
# common functions and some boilerplate.
|
||||||
|
class Window(Gtk.Window):
|
||||||
|
__gtype_name__ = "Window"
|
||||||
|
|
||||||
|
# To construct a new instance of this method, the following notable
|
||||||
|
# methods are called in this order:
|
||||||
|
# __new__(cls)
|
||||||
|
# __init__(self)
|
||||||
|
# finish_initializing(self, builder)
|
||||||
|
# __init__(self)
|
||||||
|
#
|
||||||
|
# For this reason, it's recommended you leave __init__ empty and put
|
||||||
|
# your initialization code in finish_initializing
|
||||||
|
|
||||||
|
def __new__(cls):
|
||||||
|
"""Special static method that's automatically called by Python when
|
||||||
|
constructing a new instance of this class.
|
||||||
|
|
||||||
|
Returns a fully instantiated BaseMugshotWindow object.
|
||||||
|
"""
|
||||||
|
builder = get_builder('MugshotWindow')
|
||||||
|
new_object = builder.get_object("mugshot_window")
|
||||||
|
new_object.finish_initializing(builder)
|
||||||
|
return new_object
|
||||||
|
|
||||||
|
def finish_initializing(self, builder):
|
||||||
|
"""Called while initializing this instance in __new__
|
||||||
|
|
||||||
|
finish_initializing should be called after parsing the UI definition
|
||||||
|
and creating a MugshotWindow object with it in order to finish
|
||||||
|
initializing the start of the new MugshotWindow instance.
|
||||||
|
"""
|
||||||
|
# Get a reference to the builder and set up the signals.
|
||||||
|
self.builder = builder
|
||||||
|
self.ui = builder.get_ui(self, True)
|
||||||
|
self.PreferencesDialog = None # class
|
||||||
|
self.preferences_dialog = None # instance
|
||||||
|
self.AboutDialog = None # class
|
||||||
|
|
||||||
|
self.settings = Gio.Settings("net.launchpad.mugshot")
|
||||||
|
self.settings.connect('changed', self.on_preferences_changed)
|
||||||
|
|
||||||
|
# Optional application indicator support
|
||||||
|
# Run 'quickly add indicator' to get started.
|
||||||
|
# More information:
|
||||||
|
# http://owaislone.org/quickly-add-indicator/
|
||||||
|
# https://wiki.ubuntu.com/DesktopExperienceTeam/ApplicationIndicators
|
||||||
|
try:
|
||||||
|
from mugshot import indicator
|
||||||
|
# self is passed so methods of this class can be called from indicator.py
|
||||||
|
# Comment this next line out to disable appindicator
|
||||||
|
self.indicator = indicator.new_application_indicator(self)
|
||||||
|
except ImportError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def on_mnu_contents_activate(self, widget, data=None):
|
||||||
|
show_uri(self, "ghelp:%s" % get_help_uri())
|
||||||
|
|
||||||
|
def on_mnu_about_activate(self, widget, data=None):
|
||||||
|
"""Display the about box for mugshot."""
|
||||||
|
if self.AboutDialog is not None:
|
||||||
|
about = self.AboutDialog() # pylint: disable=E1102
|
||||||
|
response = about.run()
|
||||||
|
about.destroy()
|
||||||
|
|
||||||
|
def on_mnu_preferences_activate(self, widget, data=None):
|
||||||
|
"""Display the preferences window for mugshot."""
|
||||||
|
|
||||||
|
""" From the PyGTK Reference manual
|
||||||
|
Say for example the preferences dialog is currently open,
|
||||||
|
and the user chooses Preferences from the menu a second time;
|
||||||
|
use the present() method to move the already-open dialog
|
||||||
|
where the user can see it."""
|
||||||
|
if self.preferences_dialog is not None:
|
||||||
|
logger.debug('show existing preferences_dialog')
|
||||||
|
self.preferences_dialog.present()
|
||||||
|
elif self.PreferencesDialog is not None:
|
||||||
|
logger.debug('create new preferences_dialog')
|
||||||
|
self.preferences_dialog = self.PreferencesDialog() # pylint: disable=E1102
|
||||||
|
self.preferences_dialog.connect('destroy', self.on_preferences_dialog_destroyed)
|
||||||
|
self.preferences_dialog.show()
|
||||||
|
# destroy command moved into dialog to allow for a help button
|
||||||
|
|
||||||
|
def on_mnu_close_activate(self, widget, data=None):
|
||||||
|
"""Signal handler for closing the MugshotWindow."""
|
||||||
|
self.destroy()
|
||||||
|
|
||||||
|
def on_destroy(self, widget, data=None):
|
||||||
|
"""Called when the MugshotWindow is closed."""
|
||||||
|
# Clean up code for saving application state should be added here.
|
||||||
|
Gtk.main_quit()
|
||||||
|
|
||||||
|
def on_preferences_changed(self, settings, key, data=None):
|
||||||
|
logger.debug('preference changed: %s = %s' % (key, str(settings.get_value(key))))
|
||||||
|
|
||||||
|
def on_preferences_dialog_destroyed(self, widget, data=None):
|
||||||
|
'''only affects gui
|
||||||
|
|
||||||
|
logically there is no difference between the user closing,
|
||||||
|
minimising or ignoring the preferences dialog'''
|
||||||
|
logger.debug('on_preferences_dialog_destroyed')
|
||||||
|
# to determine whether to create or present preferences_dialog
|
||||||
|
self.preferences_dialog = None
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
|
||||||
|
### BEGIN LICENSE
|
||||||
|
# This file is in the public domain
|
||||||
|
### END LICENSE
|
||||||
|
|
||||||
|
### DO NOT EDIT THIS FILE ###
|
||||||
|
|
||||||
|
'''facade - makes mugshot_lib package easy to refactor
|
||||||
|
|
||||||
|
while keeping its api constant'''
|
||||||
|
from . helpers import set_up_logging
|
||||||
|
from . Window import Window
|
||||||
|
from . mugshotconfig import get_version
|
||||||
|
|
|
@ -0,0 +1,100 @@
|
||||||
|
# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
|
||||||
|
### BEGIN LICENSE
|
||||||
|
# This file is in the public domain
|
||||||
|
### END LICENSE
|
||||||
|
|
||||||
|
### DO NOT EDIT THIS FILE ###
|
||||||
|
|
||||||
|
"""Helpers for an Ubuntu application."""
|
||||||
|
import logging
|
||||||
|
import os
|
||||||
|
|
||||||
|
from . mugshotconfig import get_data_file
|
||||||
|
from . Builder import Builder
|
||||||
|
|
||||||
|
from locale import gettext as _
|
||||||
|
|
||||||
|
def get_builder(builder_file_name):
|
||||||
|
"""Return a fully-instantiated Gtk.Builder instance from specified ui
|
||||||
|
file
|
||||||
|
|
||||||
|
:param builder_file_name: The name of the builder file, without extension.
|
||||||
|
Assumed to be in the 'ui' directory under the data path.
|
||||||
|
"""
|
||||||
|
# Look for the ui file that describes the user interface.
|
||||||
|
ui_filename = get_data_file('ui', '%s.ui' % (builder_file_name,))
|
||||||
|
if not os.path.exists(ui_filename):
|
||||||
|
ui_filename = None
|
||||||
|
|
||||||
|
builder = Builder()
|
||||||
|
builder.set_translation_domain('mugshot')
|
||||||
|
builder.add_from_file(ui_filename)
|
||||||
|
return builder
|
||||||
|
|
||||||
|
|
||||||
|
# Owais Lone : To get quick access to icons and stuff.
|
||||||
|
def get_media_file(media_file_name):
|
||||||
|
media_filename = get_data_file('media', '%s' % (media_file_name,))
|
||||||
|
if not os.path.exists(media_filename):
|
||||||
|
media_filename = None
|
||||||
|
|
||||||
|
return "file:///"+media_filename
|
||||||
|
|
||||||
|
class NullHandler(logging.Handler):
|
||||||
|
def emit(self, record):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def set_up_logging(opts):
|
||||||
|
# add a handler to prevent basicConfig
|
||||||
|
root = logging.getLogger()
|
||||||
|
null_handler = NullHandler()
|
||||||
|
root.addHandler(null_handler)
|
||||||
|
|
||||||
|
formatter = logging.Formatter("%(levelname)s:%(name)s: %(funcName)s() '%(message)s'")
|
||||||
|
|
||||||
|
logger = logging.getLogger('mugshot')
|
||||||
|
logger_sh = logging.StreamHandler()
|
||||||
|
logger_sh.setFormatter(formatter)
|
||||||
|
logger.addHandler(logger_sh)
|
||||||
|
|
||||||
|
lib_logger = logging.getLogger('mugshot_lib')
|
||||||
|
lib_logger_sh = logging.StreamHandler()
|
||||||
|
lib_logger_sh.setFormatter(formatter)
|
||||||
|
lib_logger.addHandler(lib_logger_sh)
|
||||||
|
|
||||||
|
# Set the logging level to show debug messages.
|
||||||
|
if opts.verbose:
|
||||||
|
logger.setLevel(logging.DEBUG)
|
||||||
|
logger.debug('logging enabled')
|
||||||
|
if opts.verbose > 1:
|
||||||
|
lib_logger.setLevel(logging.DEBUG)
|
||||||
|
|
||||||
|
def get_help_uri(page=None):
|
||||||
|
# help_uri from source tree - default language
|
||||||
|
here = os.path.dirname(__file__)
|
||||||
|
help_uri = os.path.abspath(os.path.join(here, '..', 'help', 'C'))
|
||||||
|
|
||||||
|
if not os.path.exists(help_uri):
|
||||||
|
# installed so use gnome help tree - user's language
|
||||||
|
help_uri = 'mugshot'
|
||||||
|
|
||||||
|
# unspecified page is the index.page
|
||||||
|
if page is not None:
|
||||||
|
help_uri = '%s#%s' % (help_uri, page)
|
||||||
|
|
||||||
|
return help_uri
|
||||||
|
|
||||||
|
def show_uri(parent, link):
|
||||||
|
from gi.repository import Gtk # pylint: disable=E0611
|
||||||
|
screen = parent.get_screen()
|
||||||
|
Gtk.show_uri(screen, link, Gtk.get_current_event_time())
|
||||||
|
|
||||||
|
def alias(alternative_function_name):
|
||||||
|
'''see http://www.drdobbs.com/web-development/184406073#l9'''
|
||||||
|
def decorator(function):
|
||||||
|
'''attach alternative_function_name(s) to function'''
|
||||||
|
if not hasattr(function, 'aliases'):
|
||||||
|
function.aliases = []
|
||||||
|
function.aliases.append(alternative_function_name)
|
||||||
|
return function
|
||||||
|
return decorator
|
|
@ -0,0 +1,58 @@
|
||||||
|
# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
|
||||||
|
### BEGIN LICENSE
|
||||||
|
# This file is in the public domain
|
||||||
|
### END LICENSE
|
||||||
|
|
||||||
|
### DO NOT EDIT THIS FILE ###
|
||||||
|
|
||||||
|
__all__ = [
|
||||||
|
'project_path_not_found',
|
||||||
|
'get_data_file',
|
||||||
|
'get_data_path',
|
||||||
|
]
|
||||||
|
|
||||||
|
# Where your project will look for your data (for instance, images and ui
|
||||||
|
# files). By default, this is ../data, relative your trunk layout
|
||||||
|
__mugshot_data_directory__ = '../data/'
|
||||||
|
__license__ = ''
|
||||||
|
__version__ = 'VERSION'
|
||||||
|
|
||||||
|
import os
|
||||||
|
|
||||||
|
from locale import gettext as _
|
||||||
|
|
||||||
|
class project_path_not_found(Exception):
|
||||||
|
"""Raised when we can't find the project directory."""
|
||||||
|
|
||||||
|
|
||||||
|
def get_data_file(*path_segments):
|
||||||
|
"""Get the full path to a data file.
|
||||||
|
|
||||||
|
Returns the path to a file underneath the data directory (as defined by
|
||||||
|
`get_data_path`). Equivalent to os.path.join(get_data_path(),
|
||||||
|
*path_segments).
|
||||||
|
"""
|
||||||
|
return os.path.join(get_data_path(), *path_segments)
|
||||||
|
|
||||||
|
|
||||||
|
def get_data_path():
|
||||||
|
"""Retrieve mugshot data path
|
||||||
|
|
||||||
|
This path is by default <mugshot_lib_path>/../data/ in trunk
|
||||||
|
and /usr/share/mugshot in an installed version but this path
|
||||||
|
is specified at installation time.
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Get pathname absolute or relative.
|
||||||
|
path = os.path.join(
|
||||||
|
os.path.dirname(__file__), __mugshot_data_directory__)
|
||||||
|
|
||||||
|
abs_data_path = os.path.abspath(path)
|
||||||
|
if not os.path.exists(abs_data_path):
|
||||||
|
raise project_path_not_found
|
||||||
|
|
||||||
|
return abs_data_path
|
||||||
|
|
||||||
|
|
||||||
|
def get_version():
|
||||||
|
return __version__
|
|
@ -0,0 +1,137 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
|
||||||
|
### BEGIN LICENSE
|
||||||
|
# This file is in the public domain
|
||||||
|
### END LICENSE
|
||||||
|
|
||||||
|
###################### DO NOT TOUCH THIS (HEAD TO THE SECOND PART) ######################
|
||||||
|
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
|
try:
|
||||||
|
import DistUtilsExtra.auto
|
||||||
|
except ImportError:
|
||||||
|
print >> sys.stderr, 'To build mugshot you need https://launchpad.net/python-distutils-extra'
|
||||||
|
sys.exit(1)
|
||||||
|
assert DistUtilsExtra.auto.__version__ >= '2.18', 'needs DistUtilsExtra.auto >= 2.18'
|
||||||
|
|
||||||
|
def update_config(libdir, values = {}):
|
||||||
|
|
||||||
|
filename = os.path.join(libdir, 'mugshot_lib/mugshotconfig.py')
|
||||||
|
oldvalues = {}
|
||||||
|
try:
|
||||||
|
fin = file(filename, 'r')
|
||||||
|
fout = file(filename + '.new', 'w')
|
||||||
|
|
||||||
|
for line in fin:
|
||||||
|
fields = line.split(' = ') # Separate variable from value
|
||||||
|
if fields[0] in values:
|
||||||
|
oldvalues[fields[0]] = fields[1].strip()
|
||||||
|
line = "%s = %s\n" % (fields[0], values[fields[0]])
|
||||||
|
fout.write(line)
|
||||||
|
|
||||||
|
fout.flush()
|
||||||
|
fout.close()
|
||||||
|
fin.close()
|
||||||
|
os.rename(fout.name, fin.name)
|
||||||
|
except (OSError, IOError), e:
|
||||||
|
print ("ERROR: Can't find %s" % filename)
|
||||||
|
sys.exit(1)
|
||||||
|
return oldvalues
|
||||||
|
|
||||||
|
|
||||||
|
def move_desktop_file(root, target_data, prefix):
|
||||||
|
# The desktop file is rightly installed into install_data. But it should
|
||||||
|
# always really be installed into prefix, because while we can install
|
||||||
|
# normal data files anywhere we want, the desktop file needs to exist in
|
||||||
|
# the main system to be found. Only actually useful for /opt installs.
|
||||||
|
|
||||||
|
old_desktop_path = os.path.normpath(root + target_data +
|
||||||
|
'/share/applications')
|
||||||
|
old_desktop_file = old_desktop_path + '/mugshot.desktop'
|
||||||
|
desktop_path = os.path.normpath(root + prefix + '/share/applications')
|
||||||
|
desktop_file = desktop_path + '/mugshot.desktop'
|
||||||
|
|
||||||
|
if not os.path.exists(old_desktop_file):
|
||||||
|
print ("ERROR: Can't find", old_desktop_file)
|
||||||
|
sys.exit(1)
|
||||||
|
elif target_data != prefix + '/':
|
||||||
|
# This is an /opt install, so rename desktop file to use extras-
|
||||||
|
desktop_file = desktop_path + '/extras-mugshot.desktop'
|
||||||
|
try:
|
||||||
|
os.makedirs(desktop_path)
|
||||||
|
os.rename(old_desktop_file, desktop_file)
|
||||||
|
os.rmdir(old_desktop_path)
|
||||||
|
except OSError as e:
|
||||||
|
print ("ERROR: Can't rename", old_desktop_file, ":", e)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
return desktop_file
|
||||||
|
|
||||||
|
def update_desktop_file(filename, target_pkgdata, target_scripts):
|
||||||
|
|
||||||
|
try:
|
||||||
|
fin = file(filename, 'r')
|
||||||
|
fout = file(filename + '.new', 'w')
|
||||||
|
|
||||||
|
for line in fin:
|
||||||
|
if 'Icon=' in line:
|
||||||
|
line = "Icon=%s\n" % (target_pkgdata + 'media/mugshot.svg')
|
||||||
|
elif 'Exec=' in line:
|
||||||
|
cmd = line.split("=")[1].split(None, 1)
|
||||||
|
line = "Exec=%s" % (target_scripts + 'mugshot')
|
||||||
|
if len(cmd) > 1:
|
||||||
|
line += " %s" % cmd[1].strip() # Add script arguments back
|
||||||
|
line += "\n"
|
||||||
|
fout.write(line)
|
||||||
|
fout.flush()
|
||||||
|
fout.close()
|
||||||
|
fin.close()
|
||||||
|
os.rename(fout.name, fin.name)
|
||||||
|
except (OSError, IOError), e:
|
||||||
|
print ("ERROR: Can't find %s" % filename)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
def compile_schemas(root, target_data):
|
||||||
|
if target_data == '/usr/':
|
||||||
|
return # /usr paths don't need this, they will be handled by dpkg
|
||||||
|
schemadir = os.path.normpath(root + target_data + 'share/glib-2.0/schemas')
|
||||||
|
if (os.path.isdir(schemadir) and
|
||||||
|
os.path.isfile('/usr/bin/glib-compile-schemas')):
|
||||||
|
os.system('/usr/bin/glib-compile-schemas "%s"' % schemadir)
|
||||||
|
|
||||||
|
|
||||||
|
class InstallAndUpdateDataDirectory(DistUtilsExtra.auto.install_auto):
|
||||||
|
def run(self):
|
||||||
|
DistUtilsExtra.auto.install_auto.run(self)
|
||||||
|
|
||||||
|
target_data = '/' + os.path.relpath(self.install_data, self.root) + '/'
|
||||||
|
target_pkgdata = target_data + 'share/mugshot/'
|
||||||
|
target_scripts = '/' + os.path.relpath(self.install_scripts, self.root) + '/'
|
||||||
|
|
||||||
|
values = {'__mugshot_data_directory__': "'%s'" % (target_pkgdata),
|
||||||
|
'__version__': "'%s'" % self.distribution.get_version()}
|
||||||
|
update_config(self.install_lib, values)
|
||||||
|
|
||||||
|
desktop_file = move_desktop_file(self.root, target_data, self.prefix)
|
||||||
|
update_desktop_file(desktop_file, target_pkgdata, target_scripts)
|
||||||
|
compile_schemas(self.root, target_data)
|
||||||
|
|
||||||
|
|
||||||
|
##################################################################################
|
||||||
|
###################### YOU SHOULD MODIFY ONLY WHAT IS BELOW ######################
|
||||||
|
##################################################################################
|
||||||
|
|
||||||
|
DistUtilsExtra.auto.setup(
|
||||||
|
name='mugshot',
|
||||||
|
version='0.1',
|
||||||
|
#license='GPL-3',
|
||||||
|
#author='Your Name',
|
||||||
|
#author_email='email@ubuntu.com',
|
||||||
|
#description='UI for managing …',
|
||||||
|
#long_description='Here a longer description',
|
||||||
|
#url='https://launchpad.net/mugshot',
|
||||||
|
cmdclass={'install': InstallAndUpdateDataDirectory}
|
||||||
|
)
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
#!/usr/bin/python
|
||||||
|
# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
|
||||||
|
### BEGIN LICENSE
|
||||||
|
# This file is in the public domain
|
||||||
|
### END LICENSE
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import os.path
|
||||||
|
import unittest
|
||||||
|
sys.path.insert(0, os.path.realpath(os.path.join(os.path.dirname(__file__), "..")))
|
||||||
|
|
||||||
|
from mugshot import AboutMugshotDialog
|
||||||
|
|
||||||
|
class TestExample(unittest.TestCase):
|
||||||
|
def setUp(self):
|
||||||
|
self.AboutMugshotDialog_members = [
|
||||||
|
'AboutDialog', 'AboutMugshotDialog', 'gettext', 'logger', 'logging']
|
||||||
|
|
||||||
|
def test_AboutMugshotDialog_members(self):
|
||||||
|
all_members = dir(AboutMugshotDialog)
|
||||||
|
public_members = [x for x in all_members if not x.startswith('_')]
|
||||||
|
public_members.sort()
|
||||||
|
self.assertEqual(self.AboutMugshotDialog_members, public_members)
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
|
@ -0,0 +1,30 @@
|
||||||
|
#!/usr/bin/python
|
||||||
|
# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
|
||||||
|
### BEGIN LICENSE
|
||||||
|
# This file is in the public domain
|
||||||
|
### END LICENSE
|
||||||
|
|
||||||
|
import unittest
|
||||||
|
import subprocess
|
||||||
|
|
||||||
|
class TestPylint(unittest.TestCase):
|
||||||
|
def test_project_errors_only(self):
|
||||||
|
'''run pylint in error only mode
|
||||||
|
|
||||||
|
your code may well work even with pylint errors
|
||||||
|
but have some unusual code'''
|
||||||
|
return_code = subprocess.call(["pylint", '-E', 'mugshot'])
|
||||||
|
# not needed because nosetests displays pylint console output
|
||||||
|
#self.assertEqual(return_code, 0)
|
||||||
|
|
||||||
|
# un-comment the following for loads of diagnostics
|
||||||
|
#~ def test_project_full_report(self):
|
||||||
|
#~ '''Only for the brave
|
||||||
|
#~
|
||||||
|
#~ you will have to make judgement calls about your code standards
|
||||||
|
#~ that differ from the norm'''
|
||||||
|
#~ return_code = subprocess.call(["pylint", 'mugshot'])
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
'you will get better results with nosetests'
|
||||||
|
unittest.main()
|
Loading…
Reference in New Issue