Initial commit with functionality.

This commit is contained in:
Sean Davis 2013-07-13 11:09:49 -04:00
parent 3d16afe6bb
commit 92118a0766
18 changed files with 1006 additions and 225 deletions

View File

@ -1 +1 @@
Copyright (C) YYYY <Your Name> <Your E-mail>
Copyright (C) 2013 Sean Davis <smd.seandavis@gmail.com>

View File

@ -1,7 +1,18 @@
#!/usr/bin/python
# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
### BEGIN LICENSE
# This file is in the public domain
# Copyright (C) 2013 Sean Davis <smd.seandavis@gmail.com>
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License version 3, as published
# by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranties of
# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
# PURPOSE. See the GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.
### END LICENSE
### DO NOT EDIT THIS FILE ###

View File

@ -1,14 +1,25 @@
<?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="license" translatable="yes"># Copyright (C) 2013 Sean Davis &lt;smd.seandavis@gmail.com&gt;
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License version 3, as published
# by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranties of
# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
# PURPOSE. See the GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program. If not, see &lt;http://www.gnu.org/licenses/&gt;.
</property><property name="copyright" translatable="yes">Copyright (C) 2013 Sean Davis &lt;smd.seandavis@gmail.com&gt;</property><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="authors">Copyright (C) 2013 Sean Davis &lt;smd.seandavis@gmail.com&gt;</property>
<property name="logo">../media/mugshot.svg</property>
<child internal-child="vbox">
<object class="GtkBox" id="dialog-vbox1">
@ -35,4 +46,4 @@
</object>
</child>
</object>
</interface>
</interface>

View File

@ -3,225 +3,340 @@
<!-- interface-requires gtk+ 3.0 -->
<!-- interface-requires mugshot_window 1.0 -->
<!-- interface-local-resource-path ../media -->
<object class="GtkImage" id="image1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="pixel_size">16</property>
<property name="icon_name">insert-image</property>
</object>
<object class="GtkImage" id="image2">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="stock">gtk-help</property>
<property name="pixel_size">16</property>
<property name="icon_name">camera-photo</property>
</object>
<object class="GtkImage" id="image3">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="pixel_size">16</property>
<property name="icon_name">document-open</property>
</object>
<object class="GtkMenu" id="image_menu">
<property name="visible">True</property>
<property name="can_focus">False</property>
<signal name="hide" handler="on_image_menu_hide" swapped="no"/>
<child>
<object class="GtkImageMenuItem" id="image_from_stock">
<property name="label" translatable="yes">Select from stock...</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="image">image1</property>
<property name="use_stock">False</property>
<signal name="activate" handler="on_image_from_stock_activate" swapped="no"/>
</object>
</child>
<child>
<object class="GtkImageMenuItem" id="image_from_camera">
<property name="label" translatable="yes">Capture from camera...</property>
<property name="visible">True</property>
<property name="sensitive">False</property>
<property name="can_focus">False</property>
<property name="image">image2</property>
<property name="use_stock">False</property>
</object>
</child>
<child>
<object class="GtkImageMenuItem" id="image_from_browse">
<property name="label" translatable="yes">Browse...</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="image">image3</property>
<property name="use_stock">False</property>
<signal name="activate" handler="on_image_from_browse_activate" swapped="no"/>
</object>
</child>
</object>
<object class="GtkListStore" id="liststore1">
<columns>
<!-- column-name filename -->
<column type="gchararray"/>
<!-- column-name stock_image -->
<column type="GdkPixbuf"/>
</columns>
</object>
<object class="MugshotWindow" id="mugshot_window">
<property name="can_focus">False</property>
<property name="title" translatable="yes">Mugshot</property>
<property name="resizable">False</property>
<property name="icon">../media/mugshot.svg</property>
<child>
<object class="GtkVBox" id="vbox1">
<object class="GtkBox" id="box1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="spacing">5</property>
<property name="border_width">12</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkMenuBar" id="menubar1">
<object class="GtkBox" id="box2">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="spacing">12</property>
<child>
<object class="GtkMenuItem" id="mnu_file">
<object class="GtkToggleButton" id="image_button">
<property name="width_request">128</property>
<property name="height_request">128</property>
<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="can_focus">True</property>
<property name="receives_default">True</property>
<property name="relief">half</property>
<signal name="clicked" handler="on_image_button_clicked" swapped="no"/>
<child>
<object class="GtkImage" id="user_image">
<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>
<property name="pixel_size">128</property>
<property name="icon_name">avatar-default</property>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkMenuItem" id="mnu_edit">
<object class="GtkBox" id="box3">
<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="orientation">vertical</property>
<property name="spacing">6</property>
<child>
<object class="GtkBox" id="box4">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="spacing">6</property>
<child>
<object class="GtkImageMenuItem" id="mnu_cut">
<property name="label">gtk-cut</property>
<object class="GtkFrame" id="frame1">
<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"/>
<property name="label_xalign">0</property>
<property name="shadow_type">none</property>
<child>
<object class="GtkAlignment" id="alignment1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="left_padding">2</property>
<child>
<object class="GtkEntry" id="first_name">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="invisible_char">•</property>
<property name="input_purpose">name</property>
</object>
</child>
</object>
</child>
<child type="label">
<object class="GtkLabel" id="label1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">&lt;b&gt;First Name&lt;/b&gt;</property>
<property name="use_markup">True</property>
</object>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkImageMenuItem" id="mnu_copy">
<property name="label">gtk-copy</property>
<object class="GtkFrame" id="frame2">
<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"/>
<property name="label_xalign">0</property>
<property name="shadow_type">none</property>
<child>
<object class="GtkAlignment" id="alignment2">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="left_padding">2</property>
<child>
<object class="GtkEntry" id="last_name">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="invisible_char">•</property>
<property name="input_purpose">name</property>
</object>
</child>
</object>
</child>
<child type="label">
<object class="GtkLabel" id="label2">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">&lt;b&gt;Last Name&lt;/b&gt;</property>
<property name="use_markup">True</property>
</object>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkImageMenuItem" id="mnu_paste">
<property name="label">gtk-paste</property>
<object class="GtkFrame" id="frame3">
<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>
<property name="label_xalign">0</property>
<property name="shadow_type">none</property>
<child>
<object class="GtkAlignment" id="alignment3">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="left_padding">2</property>
<child>
<object class="GtkEntry" id="initials">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="max_length">4</property>
<property name="invisible_char">•</property>
<property name="width_chars">4</property>
<property name="input_purpose">alpha</property>
</object>
</child>
</object>
</child>
<child type="label">
<object class="GtkLabel" id="label3">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">&lt;b&gt;Initials&lt;/b&gt;</property>
<property name="use_markup">True</property>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</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">
<child>
<object class="GtkBox" id="box5">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="spacing">6</property>
<child>
<object class="GtkImageMenuItem" id="mnu_contents">
<property name="label" translatable="yes">Contents</property>
<object class="GtkFrame" id="frame4">
<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"/>
<property name="label_xalign">0</property>
<property name="shadow_type">none</property>
<child>
<object class="GtkAlignment" id="alignment4">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="left_padding">2</property>
<child>
<object class="GtkEntry" id="home_phone">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="invisible_char">•</property>
<property name="input_purpose">phone</property>
</object>
</child>
</object>
</child>
<child type="label">
<object class="GtkLabel" id="label4">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">&lt;b&gt;Home Phone&lt;/b&gt;</property>
<property name="use_markup">True</property>
</object>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkImageMenuItem" id="mnu_about">
<property name="label">gtk-about</property>
<object class="GtkFrame" id="frame5">
<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>
<property name="label_xalign">0</property>
<property name="shadow_type">none</property>
<child>
<object class="GtkAlignment" id="alignment5">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="left_padding">2</property>
<child>
<object class="GtkEntry" id="office_phone">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="invisible_char">•</property>
<property name="input_purpose">phone</property>
</object>
</child>
</object>
</child>
<child type="label">
<object class="GtkLabel" id="label5">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">&lt;b&gt;Office Phone&lt;/b&gt;</property>
<property name="use_markup">True</property>
</object>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkButton" id="button5">
<property name="label" translatable="yes">Show Office Details</property>
<property name="visible">True</property>
<property name="sensitive">False</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="pack_type">end</property>
<property name="position">2</property>
</packing>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
</object>
<packing>
@ -231,57 +346,58 @@
</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>
<placeholder/>
</child>
<child>
<object class="GtkImage" id="image1">
<object class="GtkButtonBox" id="buttonbox1">
<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>
<property name="margin_top">12</property>
<property name="spacing">6</property>
<property name="layout_style">end</property>
<child>
<object class="GtkLabel" id="label2">
<object class="GtkButton" id="help_button">
<property name="label">gtk-help</property>
<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>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_stock">True</property>
</object>
<packing>
<property name="expand">True</property>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
<property name="secondary">True</property>
</packing>
</child>
<child>
<object class="GtkButton" id="cancel_button">
<property name="label">gtk-cancel</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_stock">True</property>
<signal name="clicked" handler="on_cancel_button_clicked" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkButton" id="apply_button">
<property name="label">gtk-apply</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_stock">True</property>
<signal name="clicked" handler="on_apply_button_clicked" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
</object>
@ -289,7 +405,265 @@ To change the behavior and edit the python code, run 'quickly edit', which will
<property name="expand">False</property>
<property name="fill">True</property>
<property name="pack_type">end</property>
<property name="position">3</property>
<property name="position">2</property>
</packing>
</child>
</object>
</child>
</object>
<object class="GtkDialog" id="password_dialog">
<property name="can_focus">False</property>
<property name="border_width">5</property>
<property name="modal">True</property>
<property name="window_position">center-always</property>
<property name="type_hint">dialog</property>
<property name="urgency_hint">True</property>
<property name="transient_for">mugshot_window</property>
<child internal-child="vbox">
<object class="GtkBox" id="dialog-vbox1">
<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="can_focus">False</property>
<property name="margin_top">12</property>
<property name="layout_style">end</property>
<child>
<object class="GtkButton" id="button1">
<property name="label">gtk-cancel</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="receives_default">True</property>
<property name="use_stock">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkButton" id="button2">
<property name="label">gtk-ok</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="receives_default">True</property>
<property name="use_stock">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</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="grid1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="border_width">6</property>
<property name="row_spacing">18</property>
<property name="column_spacing">12</property>
<child>
<object class="GtkImage" id="image4">
<property name="width_request">48</property>
<property name="height_request">48</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="xalign">0</property>
<property name="yalign">0</property>
<property name="pixel_size">48</property>
<property name="icon_name">password</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">0</property>
<property name="width">1</property>
<property name="height">2</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label6">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">&lt;big&gt;&lt;b&gt;Enter your password to change user details.&lt;/b&gt;&lt;/big&gt;</property>
<property name="use_markup">True</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">0</property>
<property name="width">2</property>
<property name="height">1</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label7">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">This is a security measure to prevent unwanted updates
to your personal information.</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">1</property>
<property name="width">2</property>
<property name="height">1</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label8">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_top">12</property>
<property name="label" translatable="yes">Password:</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">2</property>
<property name="width">1</property>
<property name="height">1</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="password_entry">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="has_focus">True</property>
<property name="margin_top">12</property>
<property name="hexpand">True</property>
<property name="visibility">False</property>
<property name="invisible_char">•</property>
<property name="input_purpose">password</property>
</object>
<packing>
<property name="left_attach">2</property>
<property name="top_attach">2</property>
<property name="width">1</property>
<property name="height">1</property>
</packing>
</child>
<child>
<object class="GtkAlignment" id="alignment6">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<placeholder/>
</child>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">2</property>
<property name="width">1</property>
<property name="height">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
</child>
<action-widgets>
<action-widget response="-6">button1</action-widget>
<action-widget response="-5">button2</action-widget>
</action-widgets>
</object>
<object class="GtkWindow" id="stock_browser">
<property name="can_focus">False</property>
<property name="title" translatable="yes">Stock Browser</property>
<property name="modal">True</property>
<property name="window_position">center-on-parent</property>
<property name="default_width">600</property>
<property name="default_height">480</property>
<property name="destroy_with_parent">True</property>
<property name="type_hint">dialog</property>
<property name="transient_for">mugshot_window</property>
<signal name="delete-event" handler="on_stock_browser_delete_event" swapped="no"/>
<child>
<object class="GtkBox" id="box6">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="border_width">12</property>
<property name="orientation">vertical</property>
<property name="spacing">12</property>
<child>
<object class="GtkScrolledWindow" id="scrolledwindow1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="shadow_type">in</property>
<child>
<object class="GtkIconView" id="stock_iconview">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="model">liststore1</property>
<child>
<object class="GtkCellRendererPixbuf" id="cellrendererpixbuf"/>
<attributes>
<attribute name="pixbuf">1</attribute>
</attributes>
</child>
</object>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkButtonBox" id="buttonbox2">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkButton" id="stock_cancel">
<property name="label">gtk-cancel</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="use_stock">True</property>
<signal name="clicked" handler="on_stock_cancel_clicked" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkButton" id="stock_ok">
<property name="label">gtk-ok</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_stock">True</property>
<signal name="clicked" handler="on_stock_ok_clicked" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</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">1</property>
</packing>
</child>
</object>

View File

@ -1,6 +1,17 @@
# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
### BEGIN LICENSE
# This file is in the public domain
# Copyright (C) 2013 Sean Davis <smd.seandavis@gmail.com>
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License version 3, as published
# by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranties of
# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
# PURPOSE. See the GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.
### END LICENSE
from locale import gettext as _

View File

@ -1,11 +1,27 @@
# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
### BEGIN LICENSE
# This file is in the public domain
# Copyright (C) 2013 Sean Davis <smd.seandavis@gmail.com>
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License version 3, as published
# by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranties of
# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
# PURPOSE. See the GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.
### END LICENSE
from locale import gettext as _
from gi.repository import Gtk # pylint: disable=E0611
import os
import pexpect
import shutil
import subprocess
from gi.repository import Gtk, Gdk, GdkPixbuf # pylint: disable=E0611
import logging
logger = logging.getLogger('mugshot')
@ -13,6 +29,24 @@ from mugshot_lib import Window
from mugshot.AboutMugshotDialog import AboutMugshotDialog
from mugshot.PreferencesMugshotDialog import PreferencesMugshotDialog
def which(command):
'''Use the system command which to get the absolute path for the given
command.'''
return subprocess.Popen(['which', command], stdout=subprocess.PIPE).stdout.read().strip()
def detach_cb(menu, widget):
'''Detach a widget from its attached widget.'''
menu.detach()
def menu_position(self, menu, data=None, something_else=None):
'''Position a menu at the bottom of its attached widget'''
widget = menu.get_attach_widget()
allocation = widget.get_allocation()
window_pos = widget.get_window().get_position()
x = window_pos[0] + allocation.x
y = window_pos[1] + allocation.y + allocation.height
return (x, y, True)
# See mugshot_lib.Window.py for more details about how this class works
class MugshotWindow(Window):
__gtype_name__ = "MugshotWindow"
@ -23,6 +57,214 @@ class MugshotWindow(Window):
self.AboutDialog = AboutMugshotDialog
self.PreferencesDialog = PreferencesMugshotDialog
self.updated_image = None
self.first_name_entry = builder.get_object('first_name')
self.last_name_entry = builder.get_object('last_name')
self.initials_entry = builder.get_object('initials')
self.office_phone_entry = builder.get_object('office_phone')
self.home_phone_entry = builder.get_object('home_phone')
self.user_image = builder.get_object('user_image')
self.image_button = builder.get_object('image_button')
self.image_menu = builder.get_object('image_menu')
self.image_menu.attach_to_widget(self.image_button, detach_cb)
self.iconview = builder.get_object('stock_iconview')
self.stock_browser = builder.get_object('stock_browser')
face = os.path.expanduser('~/.face')
if os.path.isfile(face):
self.set_user_image(face)
else:
self.set_user_image(None)
# Code for other initialization actions should be added here.
self.first_name, self.last_name, self.initials, self.office_phone, \
self.home_phone = self.get_user_details()
if self.home_phone == 'none': self.home_phone = ''
if self.office_phone == 'none': self.office_phone = ''
self.first_name_entry.set_text(self.first_name)
self.last_name_entry.set_text(self.last_name)
self.initials_entry.set_text(self.initials)
self.office_phone_entry.set_text(self.office_phone)
self.home_phone_entry.set_text(self.home_phone)
def on_image_from_browse_activate(self, widget):
chooser = Gtk.FileChooserDialog(_("Select an image"), self, Gtk.FileChooserAction.OPEN, (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, Gtk.STOCK_OK, Gtk.ResponseType.OK))
image_filter = Gtk.FileFilter()
image_filter.set_name('Images')
image_filter.add_mime_type('image/*')
chooser.add_filter(image_filter)
response = chooser.run()
if response == Gtk.ResponseType.OK:
self.updated_image = chooser.get_filename()
self.set_user_image(self.updated_image)
chooser.hide()
def on_stock_browser_delete_event(self, widget, event):
widget.hide()
return True
def on_image_from_stock_activate(self, widget):
self.load_stock_browser()
self.stock_browser.show_all()
def on_image_button_clicked(self, widget):
"""When the menu button is clicked, display the appmenu."""
if widget.get_active():
self.image_menu.popup(None, None, menu_position,
self.image_menu, 3,
Gtk.get_current_event_time())
def on_cancel_button_clicked(self, widget):
self.destroy()
def on_image_menu_hide(self, widget):
self.image_button.set_active(False)
def get_finger_details_updated(self):
if self.first_name != self.first_name_entry.get_text().strip() or \
self.last_name != self.last_name_entry.get_text().strip() or \
self.home_phone != self.home_phone_entry.get_text().strip() or \
self.office_phone != self.office_phone_entry.get_text().strip():
return True
return False
def on_apply_button_clicked(self, widget):
if self.get_finger_details_updated():
self.save_finger()
if self.updated_image:
self.save_image()
def set_user_image(self, filename=None):
if filename:
pixbuf = GdkPixbuf.Pixbuf.new_from_file(filename)
scaled = pixbuf.scale_simple(128, 128, GdkPixbuf.InterpType.HYPER)
self.user_image.set_from_pixbuf(scaled)
else:
self.user_image.set_from_icon_name('avatar-default', 128)
def load_stock_browser(self):
model = self.iconview.get_model()
if len(model) != 0:
return
for filename in os.listdir('/usr/share/pixmaps/faces'):
full_path = os.path.join('/usr/share/pixmaps/faces/', filename)
if os.path.isfile(full_path):
pixbuf = GdkPixbuf.Pixbuf.new_from_file(full_path)
scaled = pixbuf.scale_simple(90, 90, GdkPixbuf.InterpType.HYPER)
model.append([full_path, scaled])
def on_stock_cancel_clicked(self, widget):
self.stock_browser.hide()
def on_stock_ok_clicked(self, widget):
selected_items = self.iconview.get_selected_items()
if len(selected_items) != 0:
path = int(selected_items[0].to_string())
filename = self.iconview.get_model()[path][0]
self.set_user_image(filename)
self.updated_image = filename
self.stock_browser.hide()
def get_user_details(self):
# Get user finger details from /etc/passwd
username = os.getenv('USER')
for line in open('/etc/passwd', 'r'):
if line.startswith(username + ':'):
details = line.split(':')[4]
name, office, office_phone, home_phone = details.split(',', 3)
try:
first_name, last_name = name.split(' ', 1)
initials = first_name[0] + last_name[0]
except:
first_name = name
last_name = ''
initials = first_name[0]
return first_name, last_name, initials, office_phone, home_phone
def get_password(self):
# Show a password dialog to get password.
dialog = self.builder.get_object('password_dialog')
entry = self.builder.get_object('password_entry')
response = dialog.run()
dialog.hide()
if response == Gtk.ResponseType.OK:
pw = entry.get_text()
entry.set_text('')
return pw
return None
def get_entry_value(self, entry_widget):
# Get the text from an entry, changing none to ''
value = entry_widget.get_text().strip()
if value.lower() == 'none':
value = ''
return value
def save_finger(self):
return_codes = []
# Get the user's password
password = self.get_password()
if not password:
return return_codes
username = os.getenv('USER')
chfn = which('chfn')
# Get each of the updated values.
first_name = self.get_entry_value(self.first_name_entry)
last_name = self.get_entry_value(self.last_name_entry)
full_name = "%s %s" % (first_name, last_name)
full_name = full_name.strip()
office_phone = self.get_entry_value(self.office_phone_entry)
if office_phone == '':
office_phone = 'none'
home_phone = self.get_entry_value(self.home_phone_entry)
if home_phone == '':
home_phone = 'none'
# Full name can only be modified by root. Try using sudo to modify.
child = pexpect.spawn('sudo %s %s' % (chfn, username))
child.timeout = 5
try:
child.expect([".*ssword.*", pexpect.EOF])
child.sendline(password)
child.expect("Full Name.*:")
child.sendline(full_name)
for i in range(5):
child.sendline('')
except pexpect.TIMEOUT:
# Password was incorrect, or sudo rights not granted
pass
child.close()
return_codes.append(child.exitstatus)
child = pexpect.spawn('chfn')
child.expect('Password: ')
child.sendline(password)
child.expect('Room Number.*:')
child.sendline('')
child.expect('Work Phone.*:')
child.sendline(office_phone)
child.expect('Home Phone.*:')
child.sendline(home_phone)
child.sendline(home_phone)
child.close(True)
return_codes.append(child.exitstatus)
return return_codes
def save_image(self):
# Copy the updated image to .face
if not self.updated_image:
return False
face = os.path.expanduser('~/.face')
if os.path.isfile(face):
os.remove(face)
shutil.copyfile(self.updated_image, face)
self.updated_image = None
return True

View File

@ -1,6 +1,17 @@
# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
### BEGIN LICENSE
# This file is in the public domain
# Copyright (C) 2013 Sean Davis <smd.seandavis@gmail.com>
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License version 3, as published
# by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranties of
# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
# PURPOSE. See the GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.
### END LICENSE
# This is your preferences dialog.

View File

@ -1,6 +1,17 @@
# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
### BEGIN LICENSE
# This file is in the public domain
# Copyright (C) 2013 Sean Davis <smd.seandavis@gmail.com>
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License version 3, as published
# by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranties of
# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
# PURPOSE. See the GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.
### END LICENSE
import optparse

View File

@ -1,6 +1,17 @@
# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
### BEGIN LICENSE
# This file is in the public domain
# Copyright (C) 2013 Sean Davis <smd.seandavis@gmail.com>
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License version 3, as published
# by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranties of
# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
# PURPOSE. See the GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.
### END LICENSE
### DO NOT EDIT THIS FILE ###

View File

@ -1,6 +1,17 @@
# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
### BEGIN LICENSE
# This file is in the public domain
# Copyright (C) 2013 Sean Davis <smd.seandavis@gmail.com>
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License version 3, as published
# by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranties of
# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
# PURPOSE. See the GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.
### END LICENSE
### DO NOT EDIT THIS FILE ###

View File

@ -1,6 +1,17 @@
# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
### BEGIN LICENSE
# This file is in the public domain
# Copyright (C) 2013 Sean Davis <smd.seandavis@gmail.com>
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License version 3, as published
# by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranties of
# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
# PURPOSE. See the GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.
### END LICENSE
### DO NOT EDIT THIS FILE ###

View File

@ -1,6 +1,17 @@
# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
### BEGIN LICENSE
# This file is in the public domain
# Copyright (C) 2013 Sean Davis <smd.seandavis@gmail.com>
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License version 3, as published
# by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranties of
# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
# PURPOSE. See the GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.
### END LICENSE
### DO NOT EDIT THIS FILE ###

View File

@ -1,6 +1,17 @@
# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
### BEGIN LICENSE
# This file is in the public domain
# Copyright (C) 2013 Sean Davis <smd.seandavis@gmail.com>
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License version 3, as published
# by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranties of
# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
# PURPOSE. See the GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.
### END LICENSE
### DO NOT EDIT THIS FILE ###

View File

@ -1,6 +1,17 @@
# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
### BEGIN LICENSE
# This file is in the public domain
# Copyright (C) 2013 Sean Davis <smd.seandavis@gmail.com>
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License version 3, as published
# by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranties of
# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
# PURPOSE. See the GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.
### END LICENSE
### DO NOT EDIT THIS FILE ###

View File

@ -1,6 +1,17 @@
# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
### BEGIN LICENSE
# This file is in the public domain
# Copyright (C) 2013 Sean Davis <smd.seandavis@gmail.com>
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License version 3, as published
# by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranties of
# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
# PURPOSE. See the GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.
### END LICENSE
### DO NOT EDIT THIS FILE ###
@ -14,7 +25,7 @@ __all__ = [
# 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__ = ''
__license__ = 'GPL-3'
__version__ = 'VERSION'
import os

View File

@ -1,7 +1,18 @@
#!/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
# Copyright (C) 2013 Sean Davis <smd.seandavis@gmail.com>
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License version 3, as published
# by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranties of
# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
# PURPOSE. See the GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.
### END LICENSE
###################### DO NOT TOUCH THIS (HEAD TO THE SECOND PART) ######################
@ -126,7 +137,7 @@ class InstallAndUpdateDataDirectory(DistUtilsExtra.auto.install_auto):
DistUtilsExtra.auto.setup(
name='mugshot',
version='0.1',
#license='GPL-3',
license='GPL-3',
#author='Your Name',
#author_email='email@ubuntu.com',
#description='UI for managing …',

View File

@ -1,7 +1,18 @@
#!/usr/bin/python
# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
### BEGIN LICENSE
# This file is in the public domain
# Copyright (C) 2013 Sean Davis <smd.seandavis@gmail.com>
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License version 3, as published
# by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranties of
# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
# PURPOSE. See the GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.
### END LICENSE
import sys

View File

@ -1,7 +1,18 @@
#!/usr/bin/python
# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
### BEGIN LICENSE
# This file is in the public domain
# Copyright (C) 2013 Sean Davis <smd.seandavis@gmail.com>
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License version 3, as published
# by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranties of
# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
# PURPOSE. See the GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.
### END LICENSE
import unittest