TweeTabs
Reference
This
project implements a Twitter reader and manager
over GTK notebook tabs, hence its name. Each tab
represents a set of so-called strips (like users or
tweets). The graphical user interface also allows
you to define tabs as function of other tabs. These
tab operations help you at managing your Twitter
life overall.
- In this manual, the TweeTabs user is referred
to as you.
- There are FIXME notes next to every
lie below ☺.
If you are
new to TweeTabs, you might prefer to read the
TweeTabs Tutorial first.
This is
early alpha software. I do have a need as a
user for a TweeTabs alike tool, but I'm not
especially starving for developing it myself. So,
if another Twitter tool suddenly appears with
similar capabilities, and is usable enough, I might
just switch to using it instead. But as things have
been going, it now seems that TweeTabs is not far
from being fairly usable.
The project
has administrative and technical aspects.
- Technically, the three main components are
the flow of strips through interconnected tabs
and associated logic, the graphical user
interface, and the management of the Twitter
API.
- Administratively, the project has its own Web
site. The documentation only exists as a
collection of notes,
so postponing more formal writing. The
distribution uses a clonable Git repository.
Tweetabs
merely begins to be usable, yet very humbly. I may
temporarily suffer many deficiencies, knowing that
I'll adress them over time. Here are a few uneasy
problems which I find especially annoying
currently:
- When the Twitter site becomes slow, TweeTabs
becomes unbearable. The story is that I
deactivated threading. In pre-alpha, TweeTabs
used one thread for the GUI and another for
Twitter management, but this induced serious GTK
problems, and some others.
- The URLs within the tweets are still not
clickable. It should ideally be as easy as
possible to launch the loading of referenced
pages in a nearby brower.
I could
check that TweeTabs works with:
- Python 2.5 or 2.6
- pygtk 2.12 (package python-gtk or
python-gtk2)
- PIL 1.1.6 (package
python-imaging)
- simple JSON 1.9.1 or 2.0.9 (package
python-simplejson)
- twyt 0.9.2 (see
python-twyt for some more details)
It might
likely work with other versions of these, of
course.
There is a
reachable copy of my own sandbox repository for
TweeTabs. To get and install your own copy, once
you have the above pre-requisites, try these
commands:
git clone git://github.com/pinard/TweeTabs.git
cd Tweetabs
python setup.py install
If you prefer a snapshot packed with tar or
zip, just ask, and I'll happily provide one!
☺
Calling
tweetabs with the -h option produces the following
output:
A Twitter reader and personal manager.
Usage: tweetabs [OPTION]...
Options:
-h Print this help and exit
-g WIDTHxHEIGHT Set minimum geometry (default 300x200)
-c CONFIG_DIR Configuration directory (default ~/.tweetabs)
-n Do not use any default tab setup
Debugging options:
-d Disable tweet sending or destructive operations
-t Use a separate thread for the Twitter manager
-i Stay in Python when the program exits
TweeTabs
should normally be executed in a bit-mapped
display. For now at least, it is preferrable to
call it from a terminal emulator, as trace
diagnostics may be sent to standard output.
When
TweeTabs starts, it displays a window consisting of
a menu bar at the top, an area for notebooks in the
middle, and an interaction area at the bottom. The
notebooks contain tabs, which in turn contain
strips, as explained later, these altogether occupy
the bulk of the TweeTabs window, and resizing that
window mainly changes the region used for
displaying notebooks.
Above the
notebooks area, there is an horizontal set of
pull-down menus, these allow for triggering various
actions. The menu heads are File,
Tab, Strip and Help.
The
File menu contains:
- Quit, for exiting the
application.
The
Help menu contains:
The other
menus are described in the appropriate sections,
below.
A notebook
is a collection of pages such than only one is
displayed at a given time. Each page has a labelled
tab to its top, or FIXME optionally any
other side, and these labelled tabs do not overlap.
Selecting a particular tab label displays its
associated page, hiding the others.
There are
plans for allowing more than one notebook from left
to right, but there is only one currently. We do
not overly try to distinguish between a page and
its labelled tab, using tab as a
comprehensive term for both. So, we merely say that
the all notebooks (or the sole one) hold a number
of tabs.
Tabs have a
few attributes, and contents in the form of
strips.
In most
cases, a new tab is automatically given a unique
name. You FIXME may rename a tab, or delete
its name. An unnamed tab label displays an
italicized N, where N is some
distinguishing integer. The displayed name is
followed by the number of included strips. If a tab
is selected, the tab label is colored. If the tab
is frozen, it is displayed using a thinner
font.
Within a
notebook, one tab is the current tab, this is the
tab for which strips are being displayed. For
making a tab current, you left-click on a tab
label. If the window height is not sufficient for
showing all tab labels, there are two ways for
accessing tabs which are not visible:
- using the arrows above and below tab
labels,
- using the scroll wheel when the mouse is over
the tab labels
Tabs may be
reordered by dragging the tab labels and dropping
them in their new place.
Tabs are
inter-connected, so one tab may read strips from
its input tabs and send strips to its output tabs.
Strips dynamically flow along these connections.
Each tab, depending on its nature and parameters,
controls which strips it accepts, and which strips
it propagates.
Tabs are
indirectly typed from the type of strips they
contain. All strips in a tab should share the same
tab strip type, yet some strips may pertain to a
sub-type of the tab strip type. The strip type of a
tab is generally the same as the strip type of its
first input, and the strip type of other inputs
should be either the same, or a sub-type of the
same. There might be exceptions to the preceding
rules, as some operators require inputs of
different types. The important things to remember
is that tabs are strongly typed, and the tab strip
type is fixed when tabs get created.
Tabs may be
selected, or not. By selecting a tab, you identifiy
that tab as one of the arguments for some special
operations on tabs, when such operations require
arguments. When the operation is later executed, it
uses all selected tabs as arguments, and then
clears all tab selections. However, if no tab was
selected prior to such an operation, that operation
uses the current tab as its sole argument.
Tabs may be
hidden, or not. A hidden tab still exists and has
its usual behaviour, except that it is not shown in
any notebook. This is to avoid visual pollution
from tabs which are used as intermediary steps in
more complex tab computations, but are not of
direct interest to you. A hidden tab may not be the
current tab as it is not displayed, and
consequently, it may not be directly selected.
However, a hidden tab is revealed through indirect
selection — for example, you may click on Tab /
Select / Add inputs from a tab being among the
hidden tab's outputs.
Tabs may be
frozen, or not. A frozen tab becomes logically
immune to any change in its input tabs. A change in
any input has not effect on the frozen tab
contents, and is not propagated further down to its
own output tags. Unfreezing a tab, however, catches
up on all input changes and propagate them (save,
of course, for its output tabs which are themselves
frozen).
Each tab
may have associated added and
deleted strips, for keeping track of all
those strips you FIXME interactively forced
into that tab or out of a that tab. A strip may not
be part of both, the last forced addition or
removal wins. Freezing has no effect on
added or deleted strips, these are
always effective, and propagated.
The
Tab menu contains:
- Toggle select, repeated for
convenience from the Select sub-menu.
-
Configure, which gives access to a
sub-menu for tab configuration related matters:
- Rename, for FIXME changing
the name of the current tab. An empty name
means that the name gets removed, defaulting
to an internally generated name.
- Toggle frozen, which changes the
frozen state of the argument tabs.
- Hide, which merely removes all
argument tabs from the display, yet without
destroying them, and keeping all their other
effects.
-
Select, which gives access to a sub-menu
for selecting or unselecting tabs:
- Add inputs, which adds to selected
tabs all input tabs for any of the argument
tabs. If any such input tab was hidden, it is
also revealed. Negative inputs to a
difference show a different selection
color.
- Add outputs, which adds to
selected tabs all output tabs for any of the
argument tabs. If any such output tab was
hidden, it is also revealed.
- Clear all, which deselects all
tabs being selected, so none remain selected
after this action.
- Inverse, which toggles the
selected state for all existing tabs. Hidden
tabs are unaffected by this operation, they
remain hidden.
- Toggle select, which has an effect
on the current tab only.
-
Timeline, which gives access to a
sub-menu for loading tweets, and periodically
updating them afterwards, from Twitter
timelines. The timeline tabs have an artificial
limit to their capacity. The limit is preset to
200 tweets, and FIXME is configurable:
- Direct, for a tab containing
direct messages you recently received from
other users.
- Direct sent, for a tab containing
direct messages you recently sent to other
users.
- Friends, for a tab containing
tweets recently sent by any of those users
you follow. However, you do not see the
replies they send to other users, unless you
follow them as well.
- Public, for a tab containing
recent public tweets, irrelevant to whether
you follow the originator or not.
- Replies, for a tab showing tweets
which are replies to you, or which mention
your Twitter name.
- User, for a tab containing recent
tweets originating from you, or FIXME
under option, from any other specific
user.
-
Users, which gives access to a sub-menu
for creating new tabs which contents represent
a set of users (FIXME: this is not
usable yet, as only the user ids are shown):
- Followers, for a tab containing
the ids of Twitter users which subscribed to
your own tweets.
- Following, for a tab containing
the ids of Twitter users you decided to
follow.
- Id input, for a tab containing the
lines of some input file. Argument tabs are
ignored, and not cleared. The name of the
file is FIXME requested
interactively.
- Id output, for a tab which
contents gets written to an output file. The
name of the file is FIXME requested
interactively. The argument tabs which will
be union-merged into the newly created
tab.
-
Compose, which gives access to a
sub-menu for creating new tabs for which
contents are dynamically derived from the
contents of other tabs:
- FIXME Added, for a tab
created out from all forcibly added
strips from the current tab. As a side
effect, the added set is cleared, and
replaced by enough tab plumbery to
dynamically get the same effect.
- FIXME Deleted, for a tab
created out from all forcibly deleted
strips from the current tab. As a side
effect, the deleted set is cleared,
and replaced by enough tab plumbery to
dynamically get the same effect.
- Union, for a tab holding all the
strips from all argument tabs.
- Intersection, for a tab holding
only those strips common to all argument
tabs.
- Difference, for a tab holding a
copy of the current tab, yet without those
strips which appear somewhere in the other
argument tabs. For this operation, it does
not matter whether if the current tab is
selected or not.
- Delete, which FIXME deletes the
argument tabs, after due confirmation. When a tab
is deleted, each of its inputs is redirected to
all of its outputs. (Surely, there are case where
this is not the appropriate thing to do.)
Each tab is
able to display a set of strips, vertically, from
top to bottom. A strip is usually a short
text running over one or very few lines, possibly
assorted with other widgets, like images or
buttons. If there are more strips than the tab may
display at once, an elevator bar gets added to the
right of the tab, which can be used to scroll
strips in and out of the window. The mouse wheel is
usable as well.
Strips
added to a tab are always added at its end, or
bottom. Strips have a natural ordering. When strips
get inserted in bulk within a tab instead of one at
a time, they are inserted in natural order.
Strips may
be selected, or not. By selecting a strip, you
identifiy that strip as one of the arguments for
some special operations on strips, when such
operations require arguments. When the operation is
later executed, it uses all selected strips as
arguments, and then clears all strip
selections.
Each user
strip shows information about a specific user. As
long as these elements are found, a user strip
displays the profile image, the screen name, the
real name, the geographical location, an own
description, and the home Web site, using the text
as the user entered it to the Twitter site. When
the strip is selected, the image is surrounded by
two colored vertical basrs. The screen name and the
URL reference are bolded — there is no attempt to
check that the URL exists. The natural order for
user strips is alphabetical by screen name.
Each tweet
strip shows the sender profile image, the screen
name of the originator, the tweet text, the date
sent, and the Twitter tool used to send. When the
strip is selected, the image is surrounded by two
colored vertical bars. URL references, Twitter
users and hash tags are bolded in some way — yet
there is no attempt to check that these actually
exist. The natural order for tweet strips is
chronological (or more precisely, by increasing
id).
The
Strip menu contains:
- Sort all, which put back all strips of
the current tab in their natural order.
-
Select, which gives access to a sub-menu
for selecting or unselecting strips:
- Clear all, which deselects all
strips being selected, so none remain
selected after this action.
- Inverse, which toggles the
selected state for all existing strips.
The
interaction area is made of two lines: the message
line and the entry line. The first is meant for
TweeTabs to write informative messages or error
diagnostics. The second is meant for you to enter a
new tweet. (In Twitter terminology, a tweet is also
called a status.)
- The message line has a left side and a right
side.
- The left side is used to display either a
message for a completed GUI action, or a
diagnostic as a result of an interrupted GUI
action. This message or diagnostic is cleared
when you interact again with TweeTabs.
- The right side is used by the Twitter
management. As such, it is somewhat
asynchronous with your interactions It may
display a message about what is going on, a
diagnostic shown in red for any seen problem,
and two counters. The counters show how many
allowed interactions still remain, as the
Twitter site does not allow more than 100
authentified interactions per hour, and
another 100 un-authentified interactions per
hour. .
- The entry line allows you to type some text,
with basic editing capabilities as common for
text entry. The ready tweet is sent when the
Enter key is pressed, unless read-only mode
(option -r) is in effect. A Twitter
tweet may not exceed 140 characters, and a count
of the remaining space gets updated on the entry
line as you type. Some characters which
graphically display as a single character may
consume two or three characters, this is related
to UTF-8 coding.
The
configuration directory, normally
~/.tweetabs/, holds startup directive files
and cached data to speed up operations, you may
also choose to add files on your own. TweeTabs does
not requires that this directory exists. If you
elect to delete it, you are responsible for saving
your own files, that is, the files yourself crafted
or saved in there. TweeTabs will happily rebuild
its own caches.
Cache files
may become corrupted if you start two TweeTabs
instances using the same configuration directory.
Some locking FIXME should be put in place to
prevent this. Cache files in the configuration
directory may not be portable between sites, as
their format on each site depends on which database
libraries were available when Python was installed.
If cache files become corrupted, of if you move the
~/.tweetabs/ directory around, the simplest
is to delete any file having -cache in its name.
Some
configuration files use Python for a configuration
language. This does not mean that you have to know
or learn it. The normal usage may be very simple
indeed. However, sophisticated users have a lot of
power at their disposal if they want to do more
fancy initialization. If you use local variables in
such files, they get discarded as soon as the file
is read.
The
defaults.py file within the configuration
directory holds Python code to be executed prior to
initialization of the user interface. This code may
force the value of some TweeTabs options. Here is
an example:
# -*- coding: utf-8 -*-
Gui.minimum_height = 500
Twitter.user = "UserName"
Twitter.password = "UserPassword"
This merely forces the TweeTabs window to be at
least 500 pixels high, and identifies the Twitter
user, assuming that UserName is your Twitter user
name and UserPassword is the associated
password. The first line is a special comment for
the Python interpreter, saying that the file uses
Unicode UTF-8. This line is likely omitted in most
cases.
I like to
maintain my own user name and password in a
different file ~/.tweetabs/user, which has
been made unreadable by other users via the command
chmod 600 ~/tweetabs/user.
That file contains only the user name and the user
password with some whitespace to separate them. I
then replace the two lines beginning with
Twitter., above, with:
import os
contents = file(os.path.expanduser('~/.tweetabs/user')).read()
Twitter.user, Twitter.password = contents.split()
Here is a
list of variables you can set in this way:
- Gui.blanking_delay
(default 4 seconds) — the lasting time, on the
message line, for each error diagnostic issued by
the Twitter manager.
- Gui.minimum_width
(default 300 pixels) — the window should have at
least this width.
- Gui.minimum_height
(default 200 pixels) — the window should have at
least this height.
- Gui.spacing
(default 7 pixels) — the amount of white space
around widgets.
- Gui.readonly_mode
(default False) — if set to True, inhibits the actual
sending of tweets from the user interface.
- Gui.select_color
(default "red") — the color of the label
for selected tabs.
- Gui.select2_color
(default "darkmagenta") — the color of
the label for selected tabs, when with a negative
connoitation, like for supplementary arguments of
a Difference.
- Gui.user_color
(default "brown") — the usual color for
a Twitter user name.
- Gui.tag_color
(default "darkgreen") — the usual color
for a Twitter hash tag name.
- Gui.tag_url
(default "blue") — the usual color for
an HTTP link.
- Strip.image_size
(default 60 pixels) — the wanted side size of a
Twitter user profile image. Images get resized as
needed, using good anti-aliasing. However, as the
originals are usually 48 pixels, you might prefer
that size sharper resolution.
- Strip.image_loader_capacity
(default 800) — the maximum number of user
profile images kept in the memory cache, before
TweeTabs starts to forget least recently
used images.
- Twitter.user
(default None, ought to be overriden) — a string
naming your Twitter user.
- Twitter.password
(default None, ought to be overriden) — a string
giving the associated Twitter password.
The
tabsetup.py file within the configuration
directory holds Python code to be executed once the
user interface has been initialized. This code may
automate the initial setup for tabs, and how they
get computed from one another. If the
tabsetup.py file is not found, some sensible
implicit tab setup is executed instead so, by
default, TweeTabs looks like a simple Twitter
reader. If the -n option was given while calling
TweeTabs, there is no initial tab setup, neither
explicit nor implicit, and the notebook starts
empty.
Here is a
(debugging) example:
# -*- coding: utf-8 -*-
f01 = Id_input(configdir + '/01')
f02 = Id_input(configdir + '/02')
f03 = Id_input(configdir + '/03')
f10 = Id_input(configdir + '/10')
f20 = Id_input(configdir + '/20')
f30 = Id_input(configdir + '/30')
f01.set_name('F-01')
f02.set_name('F-02')
f03.set_name('F-03')
f10.set_name('F-10')
f20.set_name('F-20')
f30.set_name('F-30')
union = Union(f01, f02)
inter = Intersection(f02, f20)
diff = Difference(union, f20)
union.set_name('∨')
inter.set_name('∧')
diff.set_name('∧¬')
f99 = Id_output(configdir + '/99', diff)
le = Interactive(range(40, 43))
petit = Interactive(range(50, 55))
chaperon = Interactive(range(60, 80))
route = Interactive(range(90, 97))
The above
reads six data files in the same number of tabs. It
computes three new tabs from set operations on the
data files, and saves one of these resultats on
disk. It finally sets up four more tabs with
varying amounts of strips, meant to be
interactively altered.
f01, union, inter and petit are examples of local
variables, which are only used to convey how tabs
interact with one another. These variables have
just no meaning outside this configuration
file.
Here is a
sorted list of identifiers having a preset
meaning:
- Difference
— a tab maker function which is given a variable
number of input tabs as arguments. The tab
contents automatically copy the strips from the
first input tab, except for those strips which
appear in any other input tab.
- Followers
— a tab maker function yielding all current
followers for the user.
- Following
— a tab maker function yielding all those being
followed by the user.
- Id_input
— a tab maker function which is given a file name
as an argument. The strips are derived from the
file contents (currently, one line of the file to
a strip).
- Id_output
— a tab maker function which is given a file name
as a first argument, and a variable number of
tabs as supplementary arguments. The created tab
acts like an Union tab, and the contents is saved
within the name filed, destroying any previous
contents for this file (currently, each strip
yields one line in the file).
- Interactive
— a tab maker function which is given an iterable
sequence of values for the strips as an argument.
This tab contents is meant to be modified
interactively.
- Intersection
— a tab maker function which is given a variable
number of tabs as arguments. The tab contents
automatically reflects those strips which are
simultaneously present in all input tabs.
- Union
— a tab maker function which is given a variable
number of input tabs as arguments. The tab
contents automatically reflects all strips from
all input tabs, with duplicate removed.
- configdir
— this is the name of the configuration
directory, either ~/.tweetabs or the value
of the -c option on the
tweetabs call.
- delay
— a function which accepts, for its first two
arguments, a floating number of seconds and a
function. This function is scheduled to be called
after the time lapse, then passing it the
remaining positional or keyword arguments, if
any. The display is updated after the call; by
using a sequence of delay(0, …) rather than using
all functions directly, you get some feedback
while launching a lengthy initial tab setup.
As shown
above, tabs (as returned by the tab makers) also
have methods, among which:
- set_name
— a method changing the tab label for the string
given as an argument. The special value
None removes the label.
- select
— a method selecting the tab. Tabs are not
selected on creation.
- freeze
— a method freezing the tab. Tabs are not frozen
on creation.
- hide
— a method hiding the tab. Tabs are not hidden on
creation.
The idea
popped in my mind on 2009-04-09. Five days later, I
offered it as a "flash"
TweeTabs as a project at MontrealPython
6, hoping that someone would pick it up and do
it all for me ☺. The idea looked appealing: besides
giving me a likely satisfying Twitter reader and
versatile tool, it would have allowed me to explore
the fun idea of strip flows, and to become more
familiar with GTK. On the other hand, I did not
intend to create the tool myself, as I just do not
have enough time to work on it. I presented the
idea so it does not get plainly lost.
On
2009-05-10, to take a rest from another duty, I
took a few hours to ponder what would be implied by
tab connections and logic in the Tweetabs idea, and
merely to toy with this, wrote a few lines of
Python code. I've been surprised by the
expressiveness and density of the result.
Soon after,
on 2009-05-18, still curious about if TweeTabs is
doable or not, I undusted bits of my knowledge of
pygtk. Years ago, I used it for a few
smallish programs. Devising the skeleton of a GUI
for TweeTabs yielded initial results quite fast,
and this gave me more courage. Despite the Twitter
side of the project had no code yet, I got some
hope that I could create TweeTabs after all. So,
the next day, I formalized the project setup, and
made it visible, relying on the nice
Tomboy and my
tboy for publishing my scratch notes and raw
sketches as they occur.
On
2009-05-26, I laid out the base of a Twitter
management module to be run in its own thread, and
once again, initial results looked promising. This
was enough to get the ball rolling, and the project
started for real. (However, threading brought
annoying bugs, so I soon managed ways without it.)
TweeTabs went from pre-alpha to alpha on
2009-05-31.
- 2009-05-31 Version 0.1
— Initial release.
|