Initial project creation with Quickly!

This commit is contained in:
Sean Davis 2013-07-12 13:56:24 -04:00
commit 3d16afe6bb
31 changed files with 1691 additions and 0 deletions

3
.quickly Normal file
View File

@ -0,0 +1,3 @@
project = mugshot
version = 12.08.1
template = ubuntu-application

1
AUTHORS Normal file
View File

@ -0,0 +1 @@
Copyright (C) YYYY <Your Name> <Your E-mail>

36
bin/mugshot Executable file
View File

@ -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()

View File

@ -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>

BIN
data/media/background.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.6 KiB

74
data/media/mugshot.svg Normal file
View File

@ -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

View File

@ -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>

298
data/ui/MugshotWindow.ui Normal file
View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

BIN
help/C/figures/icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 669 B

44
help/C/index.page Normal file
View File

@ -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>

18
help/C/preferences.page Normal file
View File

@ -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>

18
help/C/topic1.page Normal file
View File

@ -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>

8
mugshot.desktop.in Normal file
View File

@ -0,0 +1,8 @@
[Desktop Entry]
_Name=Mugshot
_Comment=Mugshot application
Categories=GNOME;Utility;
Exec=mugshot
Icon=mugshot
Terminal=false
Type=Application

View File

@ -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.

28
mugshot/MugshotWindow.py Normal file
View File

@ -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.

View File

@ -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.

33
mugshot/__init__.py Normal file
View File

@ -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()

View File

@ -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)

314
mugshot_lib/Builder.py Normal file
View File

@ -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)

View File

@ -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'))

118
mugshot_lib/Window.py Normal file
View File

@ -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

14
mugshot_lib/__init__.py Normal file
View File

@ -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

100
mugshot_lib/helpers.py Normal file
View File

@ -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

View File

@ -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__

137
setup.py Normal file
View File

@ -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}
)

26
tests/test_example.py Normal file
View File

@ -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()

30
tests/test_lint.py Normal file
View File

@ -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()