~ubuntu-branches/ubuntu/natty/quickly/natty

« back to all changes in this revision

Viewing changes to data/templates/ubuntu-pygame/help/tutorial-ga.xml

  • Committer: Bazaar Package Importer
  • Author(s): Didier Roche
  • Date: 2010-03-29 19:00:48 UTC
  • mfrom: (8.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20100329190048-olhobq492x3xnztz
Tags: 0.3.90-0ubuntu1
* New release:
  Quickly core:
  - check now that --template has one argument
  - -- enables to give options to templates (unknown options and arguments
    are still given to templates but -- specify explicity what to give to
    templates commands like -h, --version...)
  - check and enable recreation of the credential if user deletes it on
    Launchpad
  - Use realpath so that we can symlink to the binary in trunk.
    (Jonathan Lange)
  - project_path_not_found is raised when data_path_not_found should be
    (originated from Philip Peitsch's patch). (LP: #497688)
  - importing command in one template from another template is now possible
    support as well "all" keyword to import all commands from a template
    into another one (take care of overridden commands too)
    (LP: #452306, #487301)
  - add an apport hook to get installed templates (LP: #411127)
  - enable option completion for templates
  - handle now version upgrade, launching script for templates and handling
    versionning on them
  - change getstarted wording (LP: #486180) - Grant
  - Quickly ship now "version" tag instead of "format" tag
  - add some templatetools to check X display
  - if a commands exit with 4, do not show "ERROR:" (case of wrong command
    usage, for instance)
  - Rewrote importing module in both bin/quickly and ubuntu-project binary
  - Add get_camel_case_name() and get_sentence_name() to templatetools
  - Refactor some code in pre_create hook()
  - Now dashes and spaces support in project name! Dealing with python and
    packaging issues for you. (LP: #493130)
  - Provide Quickly API (LP: #426480)
  - Fix some issues in the man page
  ubuntu-application Template:
  - Enabling upload to team or user ppa, as well as any ppa.
    Use --ppa ppaname or --ppa team/ppaname
    .quickly file can be used as well with ppa = ppaname or
    ppa = team/ppaname (LP: #470192)
    ppa completion is also available
  - Change BSD header by full license
  - Add MIT license
  - Fixes an error when launchpad display name contains unicode character
    (Petar Vasić)
  - Fix typo in quickly help save (Petar Vasić)
  - Adds logo.png as logo property in about dialog (LP: #478389)
    (Petar Vasić)
  - Remove lp-project-change command and add configure command.
    configure lp-project [project_name] to set/reset lp project binded to
    your Quickly project
    ppa <ppa name> to set a default ppa with your project
  - Fix ~/.selected-editor being ignored (LP: #484730)
  - Fix wrong shell completion when in a template (it wrongly proposed
    all commands followed by templates)
  - Check if we have a X display available before running "run" or launching
    GUI in "create" command.
  - add -- support in quickly run to pass options like --help, --version so
    that Quickly core don't take them.
  - enable preferences save call being called multiple times (Philip Peitsch)
  - Use realpath so that we can symlink to the binary in trunk.
  - Fixed some errors in the tutorial (Brian) (LP: #499356)
  - Fix missing import sys in setup.py (Philip Peitsch) (LP: #499712)
  - rename ubuntu-project to ubuntu-application
  - enhance quickly license (no more Copyright file, only one AUTHORS file)
    personal license needs COPYING file now (and the header will be copied in
    every files). No more # needed in those files too. Some other little
    refactoring too (LP: #469330)
  - autolicence by default on first share/release (with LP info and on GPL-3)
  - change versionning support in ubuntu application: (LP: #476814)
   + quickly share just adds -publicX to current version where X is bumped
     at each "quicky share" execution
   + quickly release remove -publicX (if any) and release with current YY.MM.
     If there is already a release with that version, it will be YY.MM.1, 
     then YY.MM.2
  - add accelerators to menu items (jens persson)
  - set correctly title dialog (Philip Peitsch) (LP: #501999)
  - about dialog box is now fully automated: (LP: #478414)
   + update copyright, authors, license (when licensing)
   + version (when sharing and releasing)
   + homepage (when changing launchpad project: release and configure)
  - add an 'add' command. $ quickly dialog … is now $ quickly add dialog …
    (LP: #438320)
  - enable automatic release and milestone built in LP, releasing and pushing
    upstream tarball (LP: #470344)
  - automatic collect and publish changelog message from commits and save
    messages used during devlopment. (LP: #476572)
  - add i18n to boiler plate (LP: #423529)
  - enable adding manual depdencies to quickly project (LP: #474639)
  - enable configure its own bzr branch and resetting parent branch even once
    already configured (quickly configure bzr <branch-path>)
  - now recommends seahorse-plugins to have a graphical prompt for signing
    package
  - rename quickly glade to quickly design (LP: #528664)
  - create command is now more flexible and enable people to inherit from
    other template more easily
  - add translation domain to gtkbuilder and fix some items that shouldn't
    been translatable (Łukasz Jernaś)
  - add apport and launchpadintegration to new and existing project once
    bounded to LP (Philip Peitsch)
  - fix spelling mistake "connexion" (Łukasz Jernaś) (LP: #532667)
  - the ubuntu-application tutorial is now internationalized and use docbook
    format. Translators, it's yours! (Shane Fagan) (LP: #525168)
  - package/share/release are now more quiet and only print something on error
    warning as a summary as with unfound packages, and so on (LP: #482915)
  - new algorithm to select good email automatically. Try to get the preferred
    email and update the AUTHOR file with it.
  - test GPG key and create one automatically if none is available. The
    corresponding public key availabity in launchpad is also checked.
    (LP: #427730, #408993)
  - add devscripts as a dependency (bug #465833), will fix all the depends
    mess later
  - bump python-distutils-extra (>= 2.18bzr1)
  ubuntu-cli Template:
  - first release using import command feature (no command written into the
    template itself). This is a basic ubuntu CLI application
  ubuntu-pygame Template:
  - first release using import command feature. python-pygame added as a
    depends
* debian/control:
  - renamed and separate in multiple packages to get a -common used with
    Quickly widgets (LP: #519633)
  - suggests python-quickly-widgets

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
<?xml version="1.0" encoding="utf-8"?>
 
2
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN" "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" [
 
3
<!ENTITY appname "<application>Quickly</application>">
 
4
<!ENTITY appversion "0.4">
 
5
]>
 
6
<book lang="ga" id="index">
 
7
 <bookinfo id="Front">
 
8
   <authorgroup>
 
9
     <author role="maintainer">
 
10
       <firstname>Shane</firstname>
 
11
       <surname>Fagan</surname>
 
12
     </author>
 
13
     <author role="maintainer">
 
14
       <firstname>Rick</firstname>
 
15
       <surname>Spencer</surname>
 
16
     </author> 
 
17
   <corpauthor>
 
18
     Canonical ltd
 
19
   </corpauthor>
 
20
   </authorgroup>
 
21
   <date>
 
22
     2010
 
23
   </date>
 
24
   <productname class="trade">&appname;</productname>
 
25
   <productnumber>&appversion;</productnumber>
 
26
   <invpartnumber>2010</invpartnumber>
 
27
   <title><application>Quickly</application> 0.4 User Guide</title>
 
28
 </bookinfo>
 
29
 
 
30
 
 
31
 <preface id="preface">
 
32
  <title>Maidir leis an treoir</title>
 
33
  <para><application>Quickly</application> is a set of choices about writing apps for Ubuntu. Out of all the wonderful richness and variety of programming for Linux, <application>Quickly</application> make some very opinionated choices about what tools to use, and how to combine them. The criteria for these choices was to make it easy and fun to write and release Linux applications, even if it's your first time trying, but also in a way that delivers the full power and flexibility of the platform. One benefit of these choices, is that it's also easier to write tools that make it even easier and more fun. So <application>Quickly</application> is also a set of commands.</para>
 
34
  <itemizedlist>
 
35
   <listitem>
 
36
    <para><link linkend="getting-started">Getting Started</link></para>
 
37
   </listitem>
 
38
  </itemizedlist>
 
39
 </preface>
 
40
 
 
41
 <chapter id="getting-started">
 
42
  <title>Getting Started</title>
 
43
  <para>Welcome to the <application>Quickly</application> tutorial. In this guide you will learn how to get started using <application>Quickly</application>.</para>
 
44
  <itemizedlist>
 
45
   <listitem>
 
46
    <para><link linkend="Quickly-part1">Introduction to <application>Quickly</application> Part 1</link></para>
 
47
   </listitem>
 
48
   <listitem>
 
49
    <para><link linkend="Quickly-part2">Introduction to <application>Quickly</application> Part 2</link></para>
 
50
   </listitem>
 
51
   <listitem>
 
52
    <para><link linkend="Quickly-part3">Introduction to <application>Quickly</application> Part 3</link></para>
 
53
   </listitem>
 
54
  </itemizedlist>
 
55
 </chapter>
 
56
 
 
57
 <chapter id="Quickly-part1">
 
58
  <title>Introduction to <application>Quickly</application> Part 1</title>
 
59
  <para>This part 1 of the <application>Quickly</application> tutorial. This part is will introduce some key <application>Quickly</application> commands, editing a user interface in Glade, and editing code in Gedit. This part of the tutorial will familiarize you with these three tools, and how they work together with python and pygtk so that you can <application>Quickly</application> build applications.</para>
 
60
  
 
61
  <para><title>Creating a <application>Quickly</application> Project</title>Creating an empty but working program couldn't be simpler. First, open a terminal window to type commands into. When it's open, type the command: </para>
 
62
  <para><code><application>Quickly</application> create ubuntu-application jotty</code></para>
 
63
  <figure>
 
64
    <graphic fileref="./images/terminal1.png"/>
 
65
  </figure>
 
66
  <para>This will create a jotty sub directory containing a complete directory tree and files for an empty python application. The command finishes by running the newly created empty application.</para>
 
67
  <figure>
 
68
    <graphic fileref="./images/application1.png"/>
 
69
  </figure>
 
70
  <para><title>Testing the Empty Application</title> They are populated and set up, and you can resize the window. Notice that <application>Quickly</application> inferred that the application title is "Jotty". Only a few of menu items do anything in the empty application, Help-&gt;About, Edit-&gt;Preferences, and File-&gt;Quit.</para>
 
71
  <figure>
 
72
    <graphic fileref="./images/application2.png"/>
 
73
  </figure>
 
74
  <para><title>Running the Application</title> 
 
75
Close the application by closing the window or using the Quit command. Since the empty application isn't installed into Ubuntu yet, you can't start the application from the application menu yet. To start the applicaton, use the terminal to first cd into the new subdirectory, and then use "<application>Quickly</application> run" to start the program.</para> 
 
76
  <para><code>cd jotty</code></para> 
 
77
  <para><code><application>Quickly</application> run</code></para>
 
78
  <figure>
 
79
    <graphic fileref="./images/terminal3.png"/>
 
80
  </figure>
 
81
  <para><title>Editing an Application</title></para>
 
82
  <para><title>Edit the User Interface in Glade</title>
 
83
<application>Quickly</application> programs use Glade to edit the user interface. Start Glade with <application>Quickly</application> in order to set up Glade for editing the empty applicaton. Don't start glade directly, or it won't load the necessary catalogue files for editing the classes that were automaticaly generated by <application>Quickly</application>.</para> 
 
84
  <para><code><application>Quickly</application> design</code></para>  
 
85
  <figure>
 
86
    <graphic fileref="./images/terminal4.png"/>
 
87
  </figure>
 
88
  <para>Glade will open with the project loaded up and ready to edit.</para>
 
89
  <figure>
 
90
    <graphic fileref="./images/glade1.png"/>
 
91
  </figure>
 
92
  <para>Use the Project Menu to choose "JottytWindow.ui" for editing.</para>
 
93
  <figure>
 
94
    <graphic fileref="./images/glade2.png"/>
 
95
  </figure>
 
96
  <para>We want to create a text area for typing into. There are some default Widgets added to the Window. We won't need these so we'll start with deleting them. Click on the label, and press delete, and it will disappear from the window.</para>
 
97
  <figure>
 
98
    <graphic fileref="./images/glade3.png"/>
 
99
  </figure>
 
100
  <figure>
 
101
    <graphic fileref="./images/glade4.png"/>
 
102
  </figure>
 
103
  <para>Do the same with the image widget. This leave us two free slots.</para> 
 
104
  <figure>
 
105
    <graphic fileref="./images/glade6.png"/>
 
106
  </figure>
 
107
  <para>We'll use the bottom slot to add a TextView widget for the user to type into. In the toolbox, click on the TextView widget. Then click in the empty slot.</para>
 
108
  <figure>
 
109
    <graphic fileref="./images/glade7.png"/>
 
110
  </figure>
 
111
  <para>Make sure you save the file in Glade, or your changes won't take! Then run the application from terminal again. The window now has a place where the user can type.</para>
 
112
  <figure>
 
113
    <graphic fileref="./images/application3.png"/>
 
114
  </figure>
 
115
  <para>Now we'll add the entry field for the title, and also a label for it. We'll use the top empty slot for that. First, click on Horizontal Box (HBox) from the "Containers" section of the pallette, and then click on the top slot. A dialog box will open, tell it that you want two items.</para>
 
116
  <figure>
 
117
    <graphic fileref="./images/glade8.png"/>
 
118
  </figure> 
 
119
  <para>The HBox is a container that arranges it's children horizontally. Add a label to the empty left hand box, and a Text Entry to the right hand one.</para>
 
120
  <figure>
 
121
    <graphic fileref="./images/glade9.png"/>
 
122
  </figure>
 
123
  <para>Before going on, let's clean up the UI just a tad here. Select the new HBox from the treeview in the inspector window. Then go to the Packing tab, and set Expand and Fill to "No".</para>
 
124
  <figure>
 
125
    <graphic fileref="./images/glade10.png"/>
 
126
  </figure>
 
127
  <para>Go to the General tab, and set spacing to 5.</para> 
 
128
  <figure>
 
129
    <graphic fileref="./images/glade11.png"/>
 
130
  </figure>
 
131
  <para>Select the label. On the general tab, set "Label" to "Name:". Set expand and fill to "no" for the label, but keep it "yes" for the entry. Set the padding for both to 5 (also on the Packing tab).</para>
 
132
  <figure>
 
133
    <graphic fileref="./images/glade12.png"/>
 
134
  </figure>
 
135
  <para><title>Add the Save, Open, and New Features</title> 
 
136
After the user types something, they may want to save it. A File-&gt;Save menu item was automatically created when the empty applicaton was created, but it's not hooked up to any code. To make Save work, we need tell the menu item what function to call, and then create a function to actually do the saving.</para>
 
137
  <para><title>Set the Signal Handler in Glade</title> 
 
138
To tell the menu item what function to call. If glade is not still open, open up the application in glade:</para> 
 
139
  <para><code><application>Quickly</application> design</code></para>
 
140
  <para>Click on the file menu, and the menu opens as if the application were running.</para>
 
141
  <figure>
 
142
    <graphic fileref="./images/glade13.png"/>
 
143
  </figure>
 
144
  <para>Choose the Save menu item, and it will be selected in Glade.</para>
 
145
  <figure>
 
146
    <graphic fileref="./images/glade14.png"/>
 
147
  </figure>
 
148
  <para>Then choose the "Signals" tab of the properties window.</para> 
 
149
  <figure>
 
150
    <graphic fileref="./images/glade15.png"/>
 
151
  </figure> 
 
152
  <para>In pygtk, menu items are "activated" when a user chooses the item from the menu.  Since we want a function to run when the user chooses Save, we want to specify a function to respond to the activate signal from the menu item. We'll call the function "save_file". Simply type the function name into the box for the activate signal.Make sure to save the glade file.</para> 
 
153
  <figure>
 
154
    <graphic fileref="./images/glade16.png"/>
 
155
  </figure> 
 
156
  <para>Note that you will need to setup the "open_file" signal and the "new_file" signal as well when you get to those functions later.</para>
 
157
<para><title>Edit the Code in Gedit</title></para>
 
158
<para><title>Set Up Tabs Correctly</title> 
 
159
Note a major gotcha here. In python spaces and tabs are totally different, but they look just the same in an editor. So being indented one tab stop is not the same as being indented four spaces, even though they might look the same. And indentation level is very important in python. You will get a lot of errors if you mix tab indentation with space indentation. Your generated project follows the python standard of using four spaces for each indentation level. So you'll either have to hit the space bar four time every time you indent, or set up your editor to use the right number of spaces for tabs.</para> 
 
160
<para>The upshot is that you should take a moment to set up your Gedit (or whatever editor you are using) to use spaces for tabs. In Gedit, select Preferences from the Edit menu, and choose the Editor tab. Then set Tab width to 4, and turn on "Insert spaces instead of tabs". Your preferences should look like this:</para>
 
161
  <figure>
 
162
    <graphic fileref="./images/gedit2.png"/>
 
163
  </figure>
 
164
<para><title>Create the Save File Signal Handler</title> 
 
165
Now you're ready to write some code. Of course just telling the glade file what signal to emit won't make the file actually save, because we haven't created the "save_file" function yet. The code for JottyWindow is stored in the file  jotty. jotty is a special python file that is the entry point for your application. Other python files in your application have the ".py" suffix.</para>
 
166
<para>Use the <application>Quickly</application> edit command to start editing your code files:</para> 
 
167
<para><code><application>Quickly</application> edit</code></para> 
 
168
<para>This will open the default Ubuntu text editor "Gedit" with any python files in the python directory.</para>
 
169
   <figure>
 
170
    <graphic fileref="./images/gedit1.png"/>
 
171
  </figure>
 
172
<para>JottyWindow.ui is now expecting to find a function JottyWindow.save_file(), so we simply add one to the JottyWindow class in the jotty file right under the on_destroy funtion.:</para> 
 
173
<para> 
 
174
    <literallayout><code>def save_file(self, widget, data=None):
 
175
        print "save"</code></literallayout></para> 
 
176
<para>This will print the word "save" to the terminal when run. The method signature is the standard signature expected in a signal handler. If you are new to python, be sure to copy the indentations exactly, as the indentation level is very important in python.</para>
 
177
<para>Save the file, and run it again:</para> 
 
178
<para><code> 
 
179
<application>Quickly</application> run
 
180
</code></para> 
 
181
<para>Choose "File-&gt;Save" from the menu, and you'll see the word "save" printing out interminal. That's all there is to hookig up the functions!</para>
 
182
   <figure>
 
183
    <graphic fileref="./images/application3_5.png"/>
 
184
  </figure>
 
185
<para><title>Implementing Save</title> 
 
186
Now we'll write a little code in the signal handler to actually save the text. Because we want it to be easy for users to do things like syncronize their Jotty documents between computers, back it up, etc... we'll use couchdb as our backend, and we'll use desktopcouch for our api. Note that if you are not interested in learning about how to save to and read from couchdb, you can just snipe the code.
 
187
Mostly likely you already have everything you need installed when you installed <application>Quickly</application>. But, you may need to install couchdb, desktopcouch, and the desktopcouch records api. The fastest way to do this is from the terminal:</para> 
 
188
<para><code>
 
189
sudo apt-get install python-desktopcouch-records
 
190
</code></para>
 
191
<para>This will install the api, and everything you need for the api to run. After desktopcouch  is installed, you can write the code. The code will do the following:</para>
 
192
  <itemizedlist>
 
193
   <listitem>
 
194
    <para>Import the stuff you'll need from desktopcouch.</para>
 
195
   </listitem>
 
196
   <listitem>
 
197
    <para>Get a reference to the couchdb database to save into.</para>
 
198
   </listitem>
 
199
   <listitem>
 
200
    <para>Get the title of the document and the text from the user interface.</para>
 
201
   </listitem>
 
202
   <listitem>
 
203
    <para>Check if there is already a document with the same title, and if so overwrite it.</para>
 
204
   </listitem>
 
205
   <listitem>
 
206
    <para>If there is not a document already, create one.</para>
 
207
   </listitem>
 
208
  </itemizedlist>
 
209
<para><title>Import the stuff you'll need from python-desktopcouch-records.</title> 
 
210
Add these import statements along with the other imports to the top of the jotty file:</para><para>
 
211
<literallayout><code>from desktopcouch.records.server import CouchDatabase
 
212
from desktopcouch.records.record import Record</code></literallayout></para>
 
213
<para><title>Get a Reference to the Database</title> 
 
214
Desktopcouch will set up a database for us, or create a new one if it's needed. We'll use "jotty" for the name of the database. Since we want this line to run every time the Jotty Window is created, put it at the end of the finish_initializing function:</para> 
 
215
<para><code> 
 
216
self.database = CouchDatabase("jotty", create=True)
 
217
</code></para>
 
218
<para>Now that we have an instance-wide reference to the database, we'll add code to the save_file function to run whenever the Save command is issued.</para> 
 
219
<para>Here's the code to pull the title out of the title entry:</para> 
 
220
<para>
 
221
<literallayout><code>#get the title for the note
 
222
title = self.builder.get_object("entry1").get_text()</code></literallayout></para>
 
223
<para><title>Here's the code to get pull the text out of the TextView:</title> 
 
224
In pygtk, TextView widgets have a text buffer that stores the text. So you ask the TextView for it's TextBuffer, and then you ask the TextBuffer for the text. You use iters to determine from which part of the text buffer you want text. Since we want all the text, it's easy to just get the start and end iters.</para> 
 
225
<para>
 
226
<literallayout><code>#get the string
 
227
buff = self.builder.get_object("textview1").get_buffer()
 
228
start_iter = buff.get_start_iter()
 
229
end_iter = buff.get_end_iter()
 
230
text = buff.get_text(start_iter,end_iter)
 
231
</code></literallayout></para>
 
232
<para><title>Saving a document to Couchdb</title> 
 
233
A record in couch is essentially a python dictionary with some extra key/value pairs to make the database work. So we can save the document to couch like this:</para> 
 
234
<para>
 
235
<literallayout><code>record_type = "http://wiki.ubuntu.com/<application>Quickly</application>/JottyDoc"
 
236
new_rec = Record({"record_type": record_type,"title":title, "text":text})
 
237
self.database.put(new_rec)</code></literallayout></para> 
 
238
<para>The "record_type" field is not strictly required, but among other things, it makes it easy to fetch the documents later. By convention, we use a url to specify the record type. This provides a place for other developers to go to read about the record type. The description only needs to be human readable. Couchdb is not a typed database, so don't expect that the url will have any kind of schema definition or anything. You can use whatever url you want, and put whatever you want at that URL.</para> 
 
239
<para><title>Check for a pre-existing note with the same title</title> 
 
240
Before we just write the new document though, we have to take note of the fact that couch will allow you to create as many documents as you want with the same title. We probably don't want this, so we we'll have to write a little code to check if there is already a document in couch with the same title, and if there is, update that document rather than create a new one.</para> 
 
241
<para>In CouchDB, you don't do a lot of data processing in the database like you would with a relational database. To be most efficient, we could use the desktopcouch API to create a view in CouchDB, but it's probably simplest just to do the necessary processing on the client for now. To do this, we'll use a desktopcouch function to retrieve all of the records of a specified record type.</para>
 
242
<para>To find and update documents with a matching title we will:</para>
 
243
  <itemizedlist>
 
244
   <listitem>
 
245
    <para>Retrieve all of the documents with the CouchDatabase.get_records function.</para>
 
246
   </listitem>
 
247
   <listitem>
 
248
    <para>Check each of the returned records for a matching title.</para>
 
249
   </listitem>
 
250
   <listitem>
 
251
    <para>If there is a match, update the record using the CouchDatabase.update_fields function and return.</para>
 
252
   </listitem>
 
253
  </itemizedlist>
 
254
<para>This all may sound very weird, but in code, it's not quite so complicated:</para> 
 
255
<para>
 
256
<literallayout><code>#get all the records
 
257
record_type = "http://wiki.ubuntu.com/<application>Quickly</application>/JottyDoc"
 
258
results = self.database.get_records(record_type = record_type,create_view = True)
 
259
#update a record that has the same title
 
260
for result in results:
 
261
    document = result.value
 
262
    if document["title"] == title:
 
263
        key = document["_id"]
 
264
        self.database.update_fields(key, {"text":text})
 
265
           return</code></literallayout></para>
 
266
<para>So the whole function should look like this:</para> 
 
267
<para> 
 
268
<literallayout><code>def save_file(self, widget, data=None): 
 
269
#get the title for the note 
 
270
    title = self.builder.get_object("entry1").get_text() 
 
271
#get the text to save 
 
272
    buff = self.builder.get_object("textview1").get_buffer() 
 
273
    start_iter = buff.get_start_iter() 
 
274
    end_iter = buff.get_end_iter() 
 
275
    text = buff.get_text(start_iter,end_iter) 
 
276
#get all the records 
 
277
    record_type = "http://wiki.ubuntu.com/<application>Quickly</application>/JottyDoc" 
 
278
    results = self.database.get_records(record_type = record_type,create_view = True) 
 
279
#update a record that has the same title 
 
280
    for result in results: 
 
281
        document = result.value 
 
282
        if document["title"] == title: 
 
283
            key = result.key 
 
284
            self.database.update_fields(key, {"text":text}) 
 
285
           return 
 
286
#if no records had the title, create it 
 
287
    new_rec = Record({"record_type":record_type,"title":title, "text":text})
 
288
    self.database.put_record(new_rec)</code></literallayout>
 
289
</para>
 
290
<para>Couchdb makes it really easy to see if your save function is working. You can just point your web browser at it and explore the database:</para>
 
291
<para>file:///home/your_user_name&gt;/.local/share/desktop-couch/couchdb.html</para>
 
292
   <figure>
 
293
    <graphic fileref="./images/couch1.png"/>
 
294
  </figure>
 
295
<para>If you are redirected to a page that doesn't work, you probably just need to clear your browser cache and try again.</para>
 
296
<para><title>Implementing Open and New</title> 
 
297
To open a saved document, the user will type the title of the document that they want to open in the text entry, and choose "Open" from the main menu. If there is no matching document there, it will just clear out the text view, ready for input. This is probably not too intuitive, so we'll add a dialog box for prompting the user for the title, but that's for later in the tutorial. For now, we'll just use the same text entry field.</para>
 
298
<para><title>Implementing Open is essentially the reverse of Save:</title> 
 
299
Follow these steps:</para>
 
300
  <itemizedlist>
 
301
   <listitem>
 
302
    <para>Add the open_file signal to the menu item in Glade.</para>
 
303
   </listitem>
 
304
   <listitem>
 
305
    <para>Retrieve all of the documents with the CouchDatabase.get_records function.</para>
 
306
   </listitem>
 
307
   <listitem>
 
308
    <para>Check each of the returned records for a matching title.</para>
 
309
   </listitem>
 
310
   <listitem>
 
311
    <para>If there is a match, pull out the text and display it in the text view.</para>
 
312
   </listitem>
 
313
  </itemizedlist>
 
314
<para>So the open_file function looks like so:</para> 
 
315
<para>
 
316
    <literallayout><code>def open_file(self, widget, data=None):
 
317
        #get the name of the document to open
 
318
        title = self.builder.get_object("entry1").get_text()
 
319
        text = ""
 
320
 
 
321
        #get all the records
 
322
        record_type = "http://wiki.ubuntu.com/<application>Quickly</application>/JottyDoc"
 
323
        results = self.database.get_records(record_type = record_type,create_view = True)
 
324
 
 
325
        #get the text if there is a matching title
 
326
        for result in results:
 
327
            document = result.value
 
328
            if document["title"] == title:
 
329
                text = document["text"]
 
330
        
 
331
        #set the UI to display the string
 
332
        buff = self.builder.get_object("textview1").get_buffer()
 
333
        buff.set_text(text)</code></literallayout></para>
 
334
<para><title>Implement New</title> 
 
335
First, add the new_file signal to the menu item in Glade, then add this code to clear out the text:</para> 
 
336
<para>
 
337
    <literallayout><code>def new_file(self, widget, data=None):
 
338
        self.builder.get_object("entry1").set_text("Note Title")
 
339
        buff = self.builder.get_object("textview1").get_buffer()
 
340
        buff.set_text("")</code></literallayout></para>
 
341
<para>To make them work, add these functions to the JottyWindow class, and save. Then go back and connect the functions to the activate signals for the Open and New menu items.</para>
 
342
<ulink url="./code/jotty">Complete jotty file</ulink>
 
343
<para><title>Saving Your Work</title> 
 
344
When <application>Quickly</application> created your application, it automatically added it to Bazaar, a source code versioning system. You can use Bazaar to roll back mistake, see code history, compare versions, etc... <application>Quickly</application> has a convenience function for backing up your work:</para> 
 
345
<para><code> 
 
346
<application>Quickly</application> save "First working version of Jotty"
 
347
</code></para> 
 
348
<para>This will call <code>bzr add</code> and then <code>bzr commit -m [your message]</code> for you.</para>
 
349
</chapter>
 
350
 <chapter id="Quickly-part2">
 
351
<title>Introduction to <application>Quickly</application> Part 2</title>
 
352
<para>In part 1, we created an application that can read and write text files, and persist them in the couchdb backend. However, the application has a hideous usability flaw, in the text box for specifying titles when saving and opening files is very confusing. In part 2, we'll fix that by adding a save and an open dialog.</para>
 
353
 
 
354
<para><title>Creating a <application>Quickly</application> Dialog</title></para>
 
355
<para><title>Creating the Empty Dialog</title>
 
356
It's simple to add an empty, but working dialog to your project. Simply specify the name of the new dialog, and it will be added automatically. Assuming that you are in the jotty project directory:</para>
 
357
<para><code>
 
358
<application>Quickly</application> dialog save
 
359
</code></para>
 
360
<para>This will add the dialog to your project.</para>
 
361
<para><title>Editing the New Dialog</title>
 
362
To edit the UI for the dialog, you'll need to load it into Glade again. If you already have an instance of glade running, you might want to go ahead and close it first, as it may get confusing if you have more than one open at a time. After closing glade, simply open it again:</para>
 
363
<para><code>
 
364
<application>Quickly</application> Design
 
365
</code></para>
 
366
<para>Then use the project menu to switch to newly created SaveDialog.ui file.</para>
 
367
   <figure>
 
368
    <graphic fileref="./images/glade17.png"/>
 
369
  </figure>
 
370
<para>Then add some widgets for the UI. Start with a Vertical Box (VBox) with two items. Put a label in the top, and an HBox in the bottom slot. In the HBox, add a label and an edit widget, just like you did for JottyWindow in part 1. Set the padding and expand properties as well.</para>
 
371
   <figure>
 
372
    <graphic fileref="./images/glade18.png"/>
 
373
  </figure>
 
374
<para><title>Code the Dialog</title>
 
375
You can use the "<application>Quickly</application> edit" command to open the SaveDialog.py file. This dialog needs very little additional code to work. Essentially, you just need a way to retrieve the string specified by the user. We'll add a qiuck accessor method for this:</para>
 
376
<para>
 
377
    <literallayout><code>@property
 
378
    def title_text(self):
 
379
        return self.builder.get_object("entry1").get_text()</code></literallayout></para>
 
380
<para>We don't need to write any code for the Ok and Cancel buttons, as they were automatically hooked up by <application>Quickly</application> when it created the dialog.</para>
 
381
<para>Before we go on to invoking the dialog, delete HBox from JottyWindow that holds the text entry and label, as we won't be needing those.</para>
 
382
   <figure>
 
383
    <graphic fileref="./images/glade19.png"/>
 
384
  </figure>
 
385
<para><title>Calling the Save Dialog</title>
 
386
To use the dialog in JottyWindow, we need to follow these steps:</para>
 
387
  <itemizedlist>
 
388
   <listitem>
 
389
    <para>Import SaveDialog in JottyWindow</para>
 
390
   </listitem>
 
391
   <listitem>
 
392
    <para>In the save_file function, create an instance of SaveDialog</para>
 
393
   </listitem>
 
394
   <listitem>
 
395
    <para>Run the Dialog</para>
 
396
   </listitem>
 
397
   <listitem>
 
398
    <para>Get the String</para>
 
399
   </listitem>
 
400
   <listitem>
 
401
    <para>Destroy the dialog</para>
 
402
   </listitem>
 
403
  </itemizedlist>
 
404
 
 
405
<para><title>Importing the SaveDialog</title>
 
406
Add the SaveDialog to the list of the imported modules at the top of the bin file of your project, so it looks like this:</para>
 
407
<para><code>
 
408
from jotty import AboutJottyDialog, PreferencesJottyDialog, SaveDialog
 
409
</code></para>
 
410
 
 
411
<para><title>Create an instance of the dialog and run it</title>
 
412
When the user chooses Save, we want to open the SaveDialog and collect the title of the note from the user. So we need to modify our save_file function.</para>
 
413
 
 
414
<para>To create an instance of the dialog, use the NewSaveDialog() function in the SaveDialog module. It's important that you don't create an instance of SaveDialog directly, as it won't have a chance to load up it's UI that way, and it won't work. So whenever you use a <application>Quickly</application> dialog, do it like this:</para>
 
415
<para><code>
 
416
        saver = SaveDialog.NewSaveDialog()
 
417
</code></para>
 
418
<para>To make the dialog appear, simply use the run() method. However, we want to check the result, so we'll need to store that in a variable. After it runs, we want to collect the string from the user, like this:</para>
 
419
<para><code>
 
420
        result = saver.run()
 
421
        title = saver.title_text
 
422
</code></para>
 
423
<para><title>Clean up the dialog</title>
 
424
We need to tell the dialog to not show itself anymore. We could call saver.hide() to make it hide, but since we don't need it hanging around, we'll just destroy it. Before we go on, though, we need to ensure that the user actually wants to save, so if we didn't get the Ok result, we should just return out of the function:</para>
 
425
<para>
 
426
        <literallayout><code>saver.destroy()
 
427
        if result != gtk.RESPONSE_OK:
 
428
            return</code></literallayout></para>
 
429
 
 
430
<para>Since we're now getting the title from the dialog instead of the text entry, we should delete the line of the code that sents it from entry1. So except for the addition of the dialog code, the save_file function looks pretty much the same as it did in part 1:</para>
 
431
 
 
432
<para>
 
433
    <literallayout><code>def save_file(self, widget, data=None):
 
434
        #get the titel from the user
 
435
        saver = SaveDialog.NewSaveDialog()
 
436
        result = saver.run()
 
437
        title = saver.title_text
 
438
 
 
439
        saver.destroy()
 
440
        if result != gtk.RESPONSE_OK:
 
441
            return
 
442
 
 
443
        #get the text to save
 
444
        buff = self.builder.get_object("textview1").get_buffer()
 
445
        start_iter = buff.get_start_iter()
 
446
        end_iter = buff.get_end_iter()
 
447
        text = buff.get_text(start_iter,end_iter)
 
448
 
 
449
        #get all the records
 
450
        record_type = "http://wiki.ubuntu.com/<application>Quickly</application>/JottyDoc"
 
451
        results = self.database.get_records(record_type = record_type,create_view = True)
 
452
 
 
453
        #update a record that has the same title
 
454
        for result in results:
 
455
            record = result.value
 
456
            if record["title"] == title:
 
457
                key = result.key
 
458
                self.database.update_fields(key, {"text":text})
 
459
                return
 
460
        
 
461
        #if no records had the title, create it  
 
462
        new_rec = Record({"record_type":record_type,"title":title, "text":text})
 
463
        self.database.put_record(new_rec)</code></literallayout></para>
 
464
<para>Now when we choose save, we get the SaveDialog instead:</para>
 
465
   <figure>
 
466
    <graphic fileref="./images/application4_5.png"/>
 
467
  </figure>
 
468
 
 
469
<para><title>Creating a Dialog with a CouchGrid</title>
 
470
We'll use a similar approach in the Open dialog that we did with Save. However, there is one big difference, we want to provide the user with a list of documents that you could choose to open. We'll use a widget called CouchGrid, which is included in the desktopcouch api for this.
 
471
</para>
 
472
<para><title>Create the Open Dialog</title></para>
 
473
<para><code>
 
474
<application>Quickly</application> dialog open
 
475
</code></para>
 
476
<para><title>Editing the New Dialog</title>
 
477
Start out by closing, and then reopening glade again:</para>
 
478
<para><code>
 
479
<application>Quickly</application> design
 
480
</code></para>
 
481
<para>Start by adding a VBox and a label in the same manner as in the Save Dialog above. Leave an empty space in the VBox. We will use code to put the CouchGrid there.</para>
 
482
   <figure>
 
483
    <graphic fileref="./images/glade20.png"/>
 
484
  </figure>
 
485
<para><title>Coding the Open Dialog</title></para>
 
486
<para><title>Creating and Adding a CouchGrid</title>
 
487
It just takes a little bit of code to add a CouchGrid to the  dialog. We need to:</para>
 
488
  <itemizedlist>
 
489
   <listitem>
 
490
    <para>Import the CouchGrid class.</para>
 
491
   </listitem>
 
492
   <listitem>
 
493
    <para>Create a CouchGrid pointing at the jotty database, and the desired record type.</para>
 
494
   </listitem>
 
495
   <listitem>
 
496
    <para>Add the CouchGrid to the dialog.</para>
 
497
   </listitem>
 
498
  </itemizedlist>
 
499
 
 
500
<para><title>Import the CouchGrid class</title>
 
501
CouchGrid is part of the desktopcouch records api, so we import it like this:</para>
 
502
<para><code>
 
503
from desktopcouch.records.couchgrid import CouchGrid
 
504
</code></para>
 
505
<para><title>Create the CouchGrid</title>
 
506
A CouchGrid needs to know three things, the name of the database, the name of the record type, and the name of the keys to use. "keys" is a list of fields that the widget will display, and by default will also use the same text for the heading of any columns. This set up should be done in the OpenDialog's finish_initalizing function. All this is easily done in code like this:
 
507
</para>
 
508
<para>
 
509
        <literallayout><code>database = "jotty"
 
510
        keys = ["title"]
 
511
        record_type = "http://wiki.ubuntu.com/<application>Quickly</application>/JottyDoc"
 
512
        self.couchgrid = CouchGrid(database, record_type=record_type,keys=keys)</code></literallayout></para>
 
513
<para><title>Add the CouchGrid to the Dialog</title>
 
514
we added the VBox to the dialog, we left an open space at the bottom. We'll use this by "packing" the CouchGrid into the VBox. We need to show it as well. So add the following lines to the finish_initializing function as well:
 
515
</para>
 
516
<para>
 
517
        <literallayout><code>self.couchgrid.show()
 
518
        self.builder.get_object("vbox1").pack_end(self.couchgrid)</code></literallayout></para>
 
519
 
 
520
<para><title>Create the get_selection function</title>
 
521
The dialog still needs a bit more code to work. It needs to return the user's selection, if there is one. To do this, we need to ask the CouchGrid what is selected. This is easy using the widgets selected_record_ids function. But the CouchGrid supports multiple selection, so we'll do the following:</para>
 
522
  <itemizedlist>
 
523
   <listitem>
 
524
    <para>Use a decorator to define the function as a property accessor.</para>
 
525
   </listitem>
 
526
   <listitem>
 
527
    <para>Get all the selected record ids.</para>
 
528
   </listitem>
 
529
   <listitem>
 
530
    <para>If none are selected, return None.</para>
 
531
   </listitem>
 
532
   <listitem>
 
533
    <para>Pick the first one and return it.</para>
 
534
   </listitem>
 
535
  </itemizedlist>
 
536
<para>So the function to add to OpenDialog looks like this:</para>
 
537
<para>
 
538
    <literallayout><code>@property
 
539
    def selected_record_id(self):
 
540
        ids = self.couchgrid.selected_record_ids
 
541
        if len(ids) &lt; 1:
 
542
            return None
 
543
        else:
 
544
            return ids[0]</code></literallayout></para>
 
545
<para><title>Using the Open Dialog</title>
 
546
Now we want to use the Open Dialog in the JottyWindow open_file function. To use it,we'll follow these steps:</para>
 
547
  <itemizedlist>
 
548
   <listitem>
 
549
    <para>Import OpenDialog in JottyWindow</para>
 
550
   </listitem>
 
551
   <listitem>
 
552
    <para>In the open_file function, create an instance of OpenDialog</para>
 
553
   </listitem>
 
554
   <listitem>
 
555
    <para>Run the Dialog</para>
 
556
   </listitem>
 
557
   <listitem>
 
558
    <para>Get the id for the selected title.</para>
 
559
   </listitem>
 
560
   <listitem>
 
561
    <para>Destroy the dialog</para>
 
562
   </listitem>   
 
563
   <listitem>
 
564
    <para>Check the response before proceeding</para>
 
565
   </listitem>   
 
566
   <listitem>
 
567
    <para>Use the id to get the record from CouchDB</para>
 
568
   </listitem>   
 
569
   <listitem>
 
570
    <para>Update the UI</para>
 
571
   </listitem>
 
572
  </itemizedlist>
 
573
 
 
574
<para><title>Import OpenDialog</title>
 
575
Just like the SaveDialog, add the import line to the list of imports:</para>
 
576
<para><code>
 
577
from jotty import AboutJottyDialog, PreferencesJottyDialog, SaveDialog, OpenDialog
 
578
</code></para>
 
579
 
 
580
<para><title>Create an instance of the dialog and run it</title>
 
581
So now we're ready to call the dialog from the JottyWindow's open_file function. Creating the OpenDialog is exactly the same as creating the SaveDialog, except we also want to tell it to load the titles before we run it:</para>
 
582
<para>
 
583
        <literallayout><code>opener = OpenDialog.NewOpenDialog()
 
584
        result = opener.run()</code></literallayout></para>
 
585
 
 
586
<para><title>Get the id for the selected title</title>
 
587
Now use the property that we created to retrieve the title and text from the dialog. Don't forget to check the response type before going on.</para>
 
588
<para>
 
589
        <literallayout><code>rec_id = opener.selected_record_id
 
590
 
 
591
        #close the dialog, and check whether to proceed
 
592
        opener.destroy()
 
593
        if result != gtk.RESPONSE_OK:
 
594
            return</code></literallayout></para>
 
595
 
 
596
 
 
597
<para><title>Use the id to get the record from CouchDB</title>
 
598
If nothing was selected, we'll just return. Otherwise, we'll retrieve the record from CouchDB and pull out the text for the document:</para>
 
599
<para>
 
600
        <literallayout><code>#get the record from CouchDB and extract the text
 
601
        if rec_id == None:
 
602
            return
 
603
        record = self.database.get_record(rec_id)
 
604
        text = record["text"]</code></literallayout></para>
 
605
 
 
606
<para><title>Update the UI</title>
 
607
Now just put the text into the texview:</para>
 
608
<para>
 
609
        <literallayout><code>#set the UI to display the string
 
610
        buff = self.builder.get_object("textview1").get_buffer()
 
611
        buff.set_text(text)</code></literallayout></para>
 
612
<para>That's all there is to it. So the whole open_file function looks like this:</para>
 
613
<para>
 
614
    <literallayout><code>def open_file(self, widget, data=None):
 
615
        #run the open dialog
 
616
        opener = OpenDialog.NewOpenDialog()
 
617
        result = opener.run()
 
618
 
 
619
        #get the record id from the dialog
 
620
        rec_id = opener.selected_record_id
 
621
 
 
622
        #close the dialog, and check whether to proceed
 
623
        opener.destroy()
 
624
        if result != gtk.RESPONSE_OK:
 
625
            return
 
626
 
 
627
        #get the record from CouchDB and extract the text
 
628
        if rec_id == None:
 
629
            return
 
630
        record = self.database.get_record(rec_id)
 
631
        text = record["text"]
 
632
 
 
633
        #set the UI to display the string
 
634
        buff = self.builder.get_object("textview1").get_buffer()
 
635
        buff.set_text(text)</code></literallayout></para>
 
636
<para>Now users get a nice open dialog:</para>
 
637
   <figure>
 
638
    <graphic fileref="./images/application5.png"/>
 
639
  </figure>
 
640
 
 
641
<para>However, the application is not complete. There are a few things left for you to do:</para>
 
642
  <itemizedlist>
 
643
   <listitem>
 
644
    <para>Set the title of the JottyWindow to display the note title. Try self.set_text(title).</para>
 
645
   </listitem>
 
646
   <listitem>
 
647
    <para>The Save command works more like "Save As". The application probably shouldn't pop up a SaveDialog every time you want to save. If it's already been saved, you probably just want to save it, but use a SaveDialog when the user choose Save As, or is saving a document for the first time.</para>
 
648
   </listitem>
 
649
   <listitem>
 
650
    <para>The OpenDialog should probably return when the user double clicks on an item in the list. Try connecting to the "select-cursor-row" signal on the TreeView, and calling self.response(gtk.RESPONSE_OK) in the handler.</para>
 
651
   </listitem>
 
652
   <listitem>
 
653
    <para>Perhaps the Ok button in the OpenDialog should be disabled if nothing is selected. Try setting the "sensitivity" in Glade, and the set_sensitive function for the Ok button.</para>
 
654
   </listitem>
 
655
   <listitem>
 
656
    <para>It would be more consistent for the Open and Close dialogs to have "Open" and "Close" for buttons instead of "Ok". You can set a different type in the properties window in Glade.</para>
 
657
   </listitem>
 
658
   <listitem>
 
659
    <para>Loading every document into the open dialog is probably a bit inefficient. Perhaps storing the document id and using that to retrieve the document would be a better implementation.</para>
 
660
   </listitem>
 
661
  </itemizedlist>
 
662
</chapter>
 
663
 
 
664
<chapter id="Quickly-part3">
 
665
<title>Introduction to <application>Quickly</application> Part 3</title>
 
666
<para>In parts 1 and 2, we showed how to create a simple Ubuntu application using <application>Quickly</application>. This section will cover how to package an application so that it is easy for you to share, and easy for other people to install.</para>
 
667
<para><title>License your Application</title>
 
668
It's important to license your code so users and other programmers know their rights in terms of redistributing or modifying it. To <application>Quickly</application> grant a GPL license to your  code, simply:</para>
 
669
  <itemizedlist>
 
670
   <listitem>
 
671
    <para>Specify your name and email address in the Copyright file.</para>
 
672
   </listitem>
 
673
   <listitem>
 
674
    <para>Run the "license" command.</para>
 
675
   </listitem>
 
676
  </itemizedlist>
 
677
 
 
678
<para><title>Specify your name and email</title>
 
679
When <application>Quickly</application> created your ubuntu application, it added a file named Copyright in the top level of the directory. Open this file in your text editor, and modify the top line so it has your name and email included. Be sure not to modify other lines as it will interfere with the next step. For example, I would change the entire file to look like this:</para>
 
680
<para>
 
681
<literallayout><code># Copyright (C) 2009 Rick Spencer rick.spencer@canonical.com
 
682
### BEGIN AUTOMATIC LICENSE GENERATION
 
683
### END AUTOMATIC LICENSE GENERATION
 
684
</code></literallayout></para>
 
685
<para><title>Run the "License" Command</title>
 
686
By default, <application>Quickly</application> will use a GPL 3 license for your project. To use this license, use this command:</para>
 
687
<para><code>
 
688
<application>Quickly</application> license
 
689
</code></para>
 
690
<para>This will add the GPL 3 license to all of your code files that you've added to your project using <application>Quickly</application>.</para>
 
691
<para>Keep in mind a couple of things:</para>
 
692
  <itemizedlist>
 
693
   <listitem>
 
694
    <para>This is a one way trip. Once you license the project, changes to the license must be done manually.</para>
 
695
   </listitem>
 
696
   <listitem>
 
697
    <para>If you prefer a GPL 2 license, you can specify that when you issue the license command:</para>  
 
698
<para><code>
 
699
<application>Quickly</application> license GPL-2
 
700
</code></para>
 
701
</listitem>
 
702
<listitem>
 
703
<para><application>Quickly</application> doesn't care what license you use, but only knows natively what files and headers to include for BSD, GPL-2, GPL-3, LGPL-2 and LGPL-3. If you prefer another license, you can simply add whatever you license you like by adding your own license in the Copyright file:</para>
 
704
<para>
 
705
<literallayout><code>### BEGIN AUTOMATIC LICENSE GENERATION
 
706
# My personal license here
 
707
### END AUTOMATIC LICENSE GENERATION</code></literallayout></para>
 
708
<para>and then run:</para>
 
709
<para><code>
 
710
<application>Quickly</application> license
 
711
</code></para>
 
712
<para>to license every files.</para>
 
713
</listitem>
 
714
<listitem>
 
715
<para>If you've added code files or other files to your project manually, you will need to add the license to those files manually or add those tags at the beginning of the file:</para>
 
716
<para>
 
717
<literallayout><code>### BEGIN LICENSE
 
718
### END LICENSE</code></literallayout></para>
 
719
</listitem>
 
720
</itemizedlist>
 
721
 
 
722
<para><title>Translate Your Application</title>
 
723
To allow for users from other countries to use your application you may want to translate it. Glade automatically creates a pot file for you but to translate strings in your code you have to:</para>
 
724
<para><code>import gettext</code></para>
 
725
<para><code>gettext.gettext("What you want translated")</code></para>
 
726
 
 
727
<para><title>Specify Application Settings</title>
 
728
You should personalize your application a little before creating the archive. This is very easy to do, as all of the files that you need have already been created, and only need a few lines changed to make them your own. To do this you should:
 
729
</para>
 
730
<itemizedlist>
 
731
<listitem><para>Personalize the Application Icon</para></listitem>
 
732
<listitem><para>Edit the Desktop File</para></listitem>
 
733
<listitem><para>Edit the setup.py File</para></listitem>
 
734
</itemizedlist>
 
735
 
 
736
<para><title>Personalize your Application Icon</title>
 
737
When users install your application, Ubuntu will display an icon next to it in the menus. You can create your own icon or edit the file called "icon.png" in the media directory (jotty/data/media). Ubuntu comes with a great image editing program called "Gimp." So you can go:</para>
 
738
<para><code>
 
739
gimp data/media/icon.png
 
740
</code></para>
 
741
   <figure>
 
742
    <graphic fileref="./images/package0.png"/>
 
743
  </figure>
 
744
<para>If you don't personalize the icon, it's ok, your app will just have the default icon, such as in the image below.
 
745
</para>
 
746
<para><title>Edit the Desktop File</title>
 
747
By default, <application>Quickly</application> Ubuntu applications are classified as "utilities", so they show up under the Accessories menu in Ubuntu. If we wanted to make Jotty show up in another category, we can do this by editing the desktop file. A desktop file is a file that describes your application to a Linux desktop. The file "jottydesktop.in" was automatically created in the jotty project directory. To change Jotty from a Utility to an Office application, edit jotty.desktop.in and change this:
 
748
</para>
 
749
<para>
 
750
<literallayout><code>[Desktop Entry]
 
751
Name=Jotty
 
752
Comment=Jotty application
 
753
Categories=GNOME;Utility;
 
754
Exec=jotty
 
755
Icon=jotty
 
756
Terminal=false
 
757
Type=Application
 
758
</code></literallayout></para>
 
759
 
 
760
<para>
 
761
to this:
 
762
</para>
 
763
<para>
 
764
<literallayout><code>[Desktop Entry]
 
765
Name=Jotty
 
766
Comment=Jotty application
 
767
Categories=GNOME;Office;
 
768
Exec=jotty
 
769
Icon=jotty
 
770
Terminal=false
 
771
Type=Application</code></literallayout></para>
 
772
<para>
 
773
There are lots more categories that you can use, all defined by the FreeDesktop spec. You can see the complete list in the <ulink url="http://standards.freedesktop.org/menu-spec/latest/apa.html">menu spec</ulink>.
 
774
</para>
 
775
<para>
 
776
<title>Edit Setup.py</title>
 
777
Finally, you should include some information in the setup.py file to tell your users a little about yourself. The setup.py file was created for you, just like the desktop file. Most of of the setup.py file shouldn't be modified, as it is just boiler plate that makes your application work properly after it has been installed. However, there is a section at the bottom of the setup.py file that you should edit to describe yourself and the application.
 
778
</para>
 
779
<para>
 
780
So I would change this section:
 
781
</para>
 
782
<para>
 
783
<literallayout><code>DistUtilsExtra.auto.setup(
 
784
    name='jotty',
 
785
    version='0.1',
 
786
    license='GPL v3',
 
787
    #author='Your Name',
 
788
    #author_email='email@ubuntu.com',
 
789
    #description='UI for managing …',
 
790
    #long_description='Here a longer description',
 
791
    #url='https://launchpad.net/jotty',
 
792
    cmdclass={'install': InstallAndUpdateDataDirectory}
 
793
    )
 
794
</code></literallayout></para>
 
795
<para>
 
796
To look like this:
 
797
</para>
 
798
<para>
 
799
<literallayout><code>DistUtilsExtra.auto.setup(
 
800
    name='jotty',
 
801
    version='0.1',
 
802
    license='GPL v3',
 
803
    author='Rick Spencer',
 
804
    author_email='rick.spencer@canonical.com',
 
805
    description='Note taking application',
 
806
    long_description='Note taking application that uses CouchDB as the backend to support easy replication across users and computers.',
 
807
    #url='https://launchpad.net/jotty',
 
808
    cmdclass={'install': InstallAndUpdateDataDirectory}
 
809
    )</code></literallayout></para>
 
810
<para>Note that the license has already been set up for you. author and author_email are updated each time you connect to Launchpad (with <application>Quickly</application> release or <application>Quickly</application> share) with your Launchpad real name and preferred email adress.</para>
 
811
<para>
 
812
Notice that Jotty doesn't have a web page yet, so I just left that line commented out. Also, you don't have to increment version number as <application>Quickly</application> share and <application>Quickly</application> release commands will make it for you..
 
813
</para>
 
814
 
 
815
<para><title>Create and Test the Debian Archive</title>
 
816
After personalizing the project, we are now ready to create the package. This is easily done by issuing the package command:
 
817
</para>
 
818
<para><code>
 
819
<application>Quickly</application> package
 
820
</code></para>
 
821
<para>This command will take a little while to discover dependencies and create all the required archives, etc... It will also report some errors as we haven't created a PGP key, for instance. None the less, when it is done, the package will be created. Using the file browser, you can see the created package next to the project directory:</para>
 
822
   <figure>
 
823
    <graphic fileref="./images/package1.png"/>
 
824
  </figure>
 
825
<para>Right now, the specific file we are interested in is "jotty_0.1_all.deb". To test it out, double click on it, to open it in Ubuntu's graphical installer program:</para>
 
826
   <figure>
 
827
    <graphic fileref="./images/package2.png"/>
 
828
  </figure>
 
829
<para>Click "Install Package" to see how it  installs onto your desktop. After chugging for a bit, you'll see that it is installed in the Applications-&gt;Office menu. If you customized your icon, you'll see that the menu uses your custom icon as well.</para>
 
830
   <figure>
 
831
    <graphic fileref="./images/package3.png"/>
 
832
  </figure>
 
833
<para><title>Now that you have a package</title>
 
834
Now that you've packaged your application, you can share the .deb file. However, if your users install their application this way, and you update the application, your users will have to find this out and resinstall. This hassle can be avoided in Ubuntu by using Personal Package Archives (or PPAs). Distrubuting your applications in this manner is covered in section 4 (not yet available).</para>
 
835
</chapter>
 
836
<chapter id="Quickly-reference">
 
837
<title><application>Quickly</application>: <application>Quickly</application> Command Reference</title>
 
838
<para>The ubuntu-application template template contains the following commands.</para>
 
839
  <itemizedlist>
 
840
   <listitem>
 
841
<xref linkend="create">create</xref>
 
842
   </listitem>
 
843
   <listitem>
 
844
<xref linkend="dialog">dialog</xref>
 
845
   </listitem>
 
846
   <listitem>
 
847
<xref linkend="edit">edit</xref>
 
848
   </listitem>
 
849
   <listitem>
 
850
<xref linkend="glade">design</xref>
 
851
   </listitem>
 
852
   <listitem>
 
853
<xref linkend="help">help</xref>
 
854
   </listitem>
 
855
   <listitem>
 
856
<xref linkend="license">license</xref>
 
857
   </listitem>
 
858
   <listitem>
 
859
<xref linkend="package">package</xref>
 
860
   </listitem>
 
861
   <listitem>
 
862
<xref linkend="release">release</xref>
 
863
   </listitem>
 
864
   <listitem>
 
865
<xref linkend="run">run</xref>
 
866
   </listitem>
 
867
   <listitem>
 
868
<xref linkend="save">save</xref>
 
869
   </listitem>
 
870
   <listitem>
 
871
<xref linkend="share">share</xref>
 
872
</listitem>
 
873
</itemizedlist>
 
874
<sect1 id="create"><title>create</title>
 
875
<para><title>create</title>
 
876
Usage:</para>
 
877
<para><code>
 
878
<application>Quickly</application> create ubuntu-application path/to/project_name</code>
 
879
</para><para>
 
880
where "project_name" is one or more words separated by an underscore and
 
881
path/to can be any existing path.
 
882
</para><para>
 
883
This will create and run a new project, including Python code, 
 
884
Glade files, and packaging files to make the project work. After
 
885
creating the project, get started by:
 
886
</para>
 
887
<itemizedlist>
 
888
<listitem><para>
 
889
Changing your working directory to the new project:</para>
 
890
<para><code>cd path/to/project_name</code></para>
 
891
</listitem><listitem>
 
892
<para>Edit the UI with Glade:</para>
 
893
<para><code><application>Quickly</application> design</code></para>
 
894
</listitem><listitem>
 
895
<para>Edit the Python code:</para>
 
896
<para><code><application>Quickly</application> edit</code></para>
 
897
</listitem>
 
898
</itemizedlist>
 
899
</sect1>
 
900
 
 
901
<sect1 id="dialog"><title>dialog</title>
 
902
<para><title>dialog</title>
 
903
Usage:</para>
 
904
<para><code><application>Quickly</application> dialog dialog_name</code></para>
 
905
<para>where dialog_name is one or more words seperated with underscore</para>
 
906
<para>
 
907
This will create:
 
908
</para>
 
909
<itemizedlist>
 
910
<listitem><para>
 
911
A subclass of gtk.Dialog called DialogNameDialog in the module DialogNameDialog.py
 
912
</para></listitem>
 
913
<listitem><para>
 
914
A glade file called DialogNameDialog.ui in the ui directory
 
915
</para></listitem>
 
916
<listitem><para>
 
917
A catalog file called dialog_name_dialog.xml also in the ui directory
 
918
</para></listitem></itemizedlist>
 
919
<para>
 
920
To edit the UI for the dialog, run:</para>
 
921
<para><code><application>Quickly</application> design
 
922
</code></para>
 
923
<para>
 
924
To edit the behavior, run:</para>
 
925
<para><code><application>Quickly</application> edit</code></para>
 
926
<para>
 
927
To use the dialog you have to invoke it from another python file:
 
928
</para>
 
929
<itemizedlist>
 
930
<listitem><para><code>
 
931
Import the dialog
 
932
import DialogNameDialog
 
933
</code></para></listitem>
 
934
<listitem><para><code>
 
935
Create an instance of the dialog
 
936
dialog = DialogNameDialog.NewDialogNameDialog()
 
937
</code></para></listitem>
 
938
<listitem><para><code>
 
939
Run the dialog and hide the dialog
 
940
result = dialog.run()
 
941
dialog.hide()
 
942
</code></para></listitem>
 
943
</itemizedlist>
 
944
</sect1>
 
945
 
 
946
<sect1 id="edit"><title>edit</title>
 
947
<para><title>edit</title>
 
948
Usage:</para>
 
949
<para><code>
 
950
<application>Quickly</application> edit
 
951
</code></para><para>
 
952
A convenience command to open all of your python files in your project 
 
953
directory in your default editor, ready for editing.
 
954
</para>
 
955
</sect1>
 
956
 
 
957
<sect1 id="glade"><title>glade</title>
 
958
<para><title>glade</title>
 
959
Usage:</para><para><code>
 
960
<application>Quickly</application> design
 
961
</code></para><para>
 
962
Opens Glade UI editor so that you can edit the UI for dialogs
 
963
and windows in your project. Note that you *must* open Glade
 
964
in this manner for <application>Quickly</application> to work. If you try to open Glade
 
965
directly, and the open the UI files, Glade will throw errors
 
966
and won't open the files.
 
967
</para>
 
968
</sect1>
 
969
 
 
970
<sect1 id="help"><title>help</title>
 
971
<para><title>help</title>
 
972
Usage:</para><para><code>
 
973
<application>Quickly</application> help
 
974
</code></para><para>
 
975
Opens a web browser with the help index.
 
976
</para>
 
977
</sect1>
 
978
 
 
979
<sect1 id="license"><title>license</title>
 
980
<para><title>license</title>
 
981
Usage:</para><para><code>
 
982
<application>Quickly</application> license &lt;Your_Licence=
 
983
</code></para><para>
 
984
Adds license to project files. Before using this command, you should:
 
985
</para>
 
986
<itemizedlist>
 
987
<listitem><para>
 
988
run <application>Quickly</application> save in case something goes wrong
 
989
</para></listitem>
 
990
<listitem><para>
 
991
Edit the file Copyright to include your authorship.
 
992
</para></listitem><listitem><para>
 
993
If you want to put your own <application>Quickly</application> unsupported Licence, remove and replace the tags
 
994
   ### BEGIN AUTOMATIC LICENCE GENERATION and ### END AUTOMATIC LICENCE GENERATION
 
995
   in it by your own licence.
 
996
</para></listitem><listitem><para>
 
997
Executes either <code><application>Quickly</application> license</code> or <code><application>Quickly</application> licence &lt;License=</code>
 
998
   where &lt;License= can be either:
 
999
   - GPL-3 (default)
 
1000
   - GPL-2
 
1001
</para></listitem>
 
1002
</itemizedlist>
 
1003
<para>
 
1004
This will modify the Copyright file with the chosen licence (with GPL-3 by default).
 
1005
Updating previous chosen Licence if needed.
 
1006
If you previously removed the tags to add your own licence, it will leave it pristine.
 
1007
If no name is attributed to the Copyright, it will try to retrieve it from Launchpad
 
1008
(in <application>Quickly</application> release or <application>Quickly</application> share command only)
 
1009
</para><para>
 
1010
Finally, this will copy the Copyright at the head of every files.
 
1011
</para><para>
 
1012
Note that if you don't run <application>Quickly</application> licence before calling <application>Quickly</application> release or <application>Quickly</application>
 
1013
share, this one will execute it for you and guess the copyright holder from your
 
1014
launchpad account if you didn't update it.
 
1015
</para>
 
1016
</sect1>
 
1017
 
 
1018
<sect1 id="package"><title>package</title>
 
1019
<para><title>package</title>
 
1020
Usage:</para><para><code>
 
1021
<application>Quickly</application> package
 
1022
</code></para><para>
 
1023
Creates a debian file (deb) from your project. Before running
 
1024
the package command you can edit the Icon and Category entry of *.desktop.in 
 
1025
file, where * is the name of your project.
 
1026
</para><para>
 
1027
Note that if you didn't run <application>Quickly</application> release, <application>Quickly</application> share
 
1028
or <application>Quickly</application> change-lp-project you may miss the name, email in
 
1029
setup.py. You can edit them if you don't want to use any of these
 
1030
commands afterwards. Those changes are not a mandatory at all for
 
1031
testing purpose.
 
1032
</para>
 
1033
</sect1>
 
1034
 
 
1035
<sect1 id="release"><title>release</title>
 
1036
<para><title>release</title>
 
1037
Usage:</para><para><code>
 
1038
<application>Quickly</application> release
 
1039
</code></para><para>
 
1040
Posts a release of your project to a PPA on launchpad so that
 
1041
users can install the application on their system. 
 
1042
</para><para>
 
1043
You can also execute:
 
1044
<code><application>Quickly</application> release &lt;release_number=</code> of you don't want to use current
 
1045
release_number. The release_number must be a number.
 
1046
</para><para>
 
1047
<code><application>Quickly</application> release &lt;release_number=</code> notes about changes
 
1048
where "notes about changes" is optional text describing what changes
 
1049
were made since the last save
 
1050
</para><para>
 
1051
Before running <application>Quickly</application> release, you should: create your account
 
1052
and a project page on http://launchpad.net.
 
1053
You also have to add a PPA to your launchpad account.
 
1054
</para><para>
 
1055
Name, email and version setup.py will be automatically changed.
 
1056
(version will be &lt;current_release= and bzr will commit and tagged.
 
1057
Once the release is done,  &lt;current_release= will be incremented
 
1058
by 0.1 to be ready for next release.
 
1059
</para><para>
 
1060
If you previously used <application>Quickly</application> shared &lt;current_release=~publicX
 
1061
will be dropped to release &lt;current_release= version
 
1062
(&lt;current_release=~publicX      &lt;current_release=)
 
1063
You can modify the description and long description if you wish.
 
1064
</para><para>
 
1065
You can run <code><application>Quickly</application> package</code> and test your package to make sure it
 
1066
installs as expected. (This is not mandatory)
 
1067
</para>
 
1068
</sect1>
 
1069
 
 
1070
<sect1 id="run"><title>run</title>
 
1071
<para><title>run</title>
 
1072
Usage:</para><para><code>
 
1073
<application>Quickly</application> run
 
1074
</code></para><para>
 
1075
Runs your application. This is the best way to try test it out
 
1076
while you are developing it. It starts up the main project window.
 
1077
</para>
 
1078
</sect1>
 
1079
 
 
1080
<sect1 id="save"><title>save</title>
 
1081
<para><title>save</title>
 
1082
Usage:</para><para><code>
 
1083
<application>Quickly</application> save notes about changes
 
1084
</code></para><para>
 
1085
where "notes about changes" is optional text describing what changes
 
1086
were made since the last save.
 
1087
</para><para>
 
1088
This command commits all changes since the last save to bzr. Note that 
 
1089
it does not push changes to any back up location. If you need revert
 
1090
or otherwise use the revision control, use bzr directly:
 
1091
<code>bzr help</code>
 
1092
</para>
 
1093
</sect1>
 
1094
 
 
1095
<sect1 id="share"><title>share</title>
 
1096
<para>
 
1097
<title>share</title>
 
1098
Usage:</para><para><code>
 
1099
<application>Quickly</application> share</code>
 
1100
</para><para>
 
1101
Updates your PPA with the the latest saved project changes.
 
1102
</para><para>
 
1103
Before running <application>Quickly</application> release, you should: create your account
 
1104
on http://launchpad.net.
 
1105
You also have to add a PPA to your launchpad account.
 
1106
</para><para>
 
1107
Name, email and version setup.py will be automatically changed.
 
1108
(version will be &lt;current_release~publicX= where X will be incremented
 
1109
at each <application>Quickly</application> share execution)
 
1110
You can modify the description and long description if you wish.
 
1111
</para>
 
1112
</sect1>
 
1113
</chapter>
 
1114
 
 
1115
<chapter id="Quickly-links">
 
1116
<title>Links</title>
 
1117
<para>
 
1118
<link linkend="Quickly-reference"><application>Quickly</application>: <application>Quickly</application> Command Reference</link>
 
1119
  <itemizedlist>
 
1120
   <listitem>
 
1121
    <para><ulink url="http://blog.didrocks.fr/index.php/post/Build-your-application-Quickly-with-Quickly%3A-part1">Blog post on <application>Quickly</application></ulink></para>
 
1122
   </listitem>
 
1123
   <listitem>
 
1124
    <para><ulink url="http://docs.python.org/reference/">Language: Python Language Reference</ulink></para>
 
1125
   </listitem>
 
1126
   <listitem>
 
1127
    <para><ulink url="http://www.python.org/doc/2.6/library/index.html">Core Library: Python 2.6 Library Reference</ulink></para>
 
1128
   </listitem>
 
1129
   <listitem>
 
1130
    <para><ulink url="http://www.pygtk.org/docs/pygtk/">UI Library: PyGtk</ulink></para>
 
1131
   </listitem>
 
1132
   <listitem>
 
1133
    <para><ulink url="http://wiki.apache.org/couchdb/Reference">Database: CouchDB Reference</ulink></para>
 
1134
   </listitem>
 
1135
   <listitem>
 
1136
    <ulink url="http://library.gnome.org/devel/glade/stable/">UI Editing: Glade User Documenation</ulink>
 
1137
   </listitem>
 
1138
   <listitem>
 
1139
    <ulink url="http://library.gnome.org/users/gedit/stable/index.html">Editor: Gedit Help</ulink>
 
1140
   </listitem>
 
1141
   <listitem>
 
1142
    <ulink url="http://doc.bazaar-vcs.org/bzr.dev/en/user-reference/bzr_man.html">Version Control: Bazaar</ulink>
 
1143
   </listitem>
 
1144
  </itemizedlist>
 
1145
</para>
 
1146
</chapter>
 
1147
</book>