Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/ghini-1.0-dev' into ghini-1.0-dev
Browse files Browse the repository at this point in the history
  • Loading branch information
weblate committed Mar 31, 2018
2 parents c600de4 + 07f1947 commit 415e586
Show file tree
Hide file tree
Showing 47 changed files with 1,346 additions and 396 deletions.
9 changes: 6 additions & 3 deletions bauble/editor.py
Original file line number Diff line number Diff line change
Expand Up @@ -2111,13 +2111,16 @@ def on_activate_browse_button(self, widget, data=None):
fileChooserDialog.run()
filename = fileChooserDialog.get_filename()
if filename:
## rememberl chosen location for next time
## copy file to picture_root_dir (if not yet there).
## remember chosen location for next time
PictureBox.last_folder, basename = os.path.split(unicode(filename))
logger.debug('new current folder is: %s' % self.last_folder)
utils.copy_picture_with_thumbnail(self.last_folder, basename)
## copy file to picture_root_dir (if not yet there),
## also receiving thumbnail base64
thumb = utils.copy_picture_with_thumbnail(self.last_folder, basename)
## make sure the category is <picture>
self.set_model_attr('category', u'<picture>')
## append thumbnail base64 to content string
basename = basename + "|data:image/jpeg;base64," + thumb
## store basename in note field and fire callbacks.
self.set_model_attr('note', basename)
self.set_content(basename)
Expand Down
Binary file added bauble/images/ghini-tour.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
99 changes: 99 additions & 0 deletions bauble/images/ghini-tour.svg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
35 changes: 35 additions & 0 deletions bauble/images/ghini.svg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
39 changes: 21 additions & 18 deletions bauble/images/icon.svg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 0 additions & 2 deletions bauble/plugins/plants/default/genus.txt
Original file line number Diff line number Diff line change
Expand Up @@ -19055,7 +19055,6 @@
19059,"Richardsiella","Elffers & Kenn.-O'Byrne",214
19060,"Hesperostipa","(Elias) Barkworth",214
19061,"Dichelachne","Endl.",214
19062,"Saxipoa","",214
19063,"Spathia","Ewart",214
19064,"Rehia","Fijten",214
19065,"Ophiochloa","Filg. et al.",214
Expand Down Expand Up @@ -23154,7 +23153,6 @@
23163,"Pongati","Adans.",1286
23164,"Rapinia","Lour.",1286
23165,"Sphenoclea","Gaertn.",1286
23166,"Spiroplasma","",1289
23167,"Stachyurus","Siebold & Zucc.",443
23168,"Ochranthe","Lindl.",446
23169,"Jahnia","Pittier & S. F. Blake",446
Expand Down
11 changes: 6 additions & 5 deletions bauble/ui.py
Original file line number Diff line number Diff line change
Expand Up @@ -429,8 +429,8 @@ def create_main_menu(self):
# create and addaction group for menu actions
menu_actions = gtk.ActionGroup("MenuActions")
menu_actions.add_actions([("file", None, _("_File")),
#("file_new", gtk.STOCK_NEW, _("_New"),
# None, None, self.on_file_menu_new),
("file_new", gtk.STOCK_NEW, _("_New"),
None, None, self.on_file_menu_new),
("file_open", gtk.STOCK_OPEN, _("_Open"),
'<ctrl>o', None, self.on_file_menu_open),
("file_quit", gtk.STOCK_QUIT, _("_Quit"),
Expand Down Expand Up @@ -465,6 +465,8 @@ def create_main_menu(self):
("help_about", gtk.STOCK_ABOUT, _("About"),
None, None, self.on_help_menu_about),
])
menu_actions.get_action('file_new').set_sensitive(False)
menu_actions.get_action('file_open').set_sensitive(False)
self.ui_manager.insert_action_group(menu_actions, 0)

# TODO: The menubar was made available in gtk.Builder in Gtk+
Expand Down Expand Up @@ -682,10 +684,9 @@ def on_file_menu_open(self, widget, data=None):
"""
Open the connection manager.
"""
from connmgr import ConnMgrPresenter
from connmgr import start_connection_manager
default_conn = prefs[bauble.conn_default_pref]
cm = ConnMgrPresenter(default=default_conn)
name, uri = cm.start()
name, uri = start_connection_manager(default_conn)
if name is None:
return

Expand Down
21 changes: 20 additions & 1 deletion bauble/utils/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ def get(self, key, getter, on_hit=lambda x: None):
def copy_picture_with_thumbnail(path, basename=None):
"""copy file from path to picture_root, and make thumbnail, preserving name
return base64 representation of thumbnail
"""
import os.path
if basename is None:
Expand All @@ -110,16 +111,23 @@ def copy_picture_with_thumbnail(path, basename=None):
from PIL import Image
full_dest_path = os.path.join(prefs.prefs[prefs.picture_root_pref],
'thumbs', basename)
result = ""
try:
im = Image.open(filename)
im.thumbnail((400, 400))
logger.debug('copying %s to %s' % (filename, full_dest_path))
im.save(full_dest_path)
from io import BytesIO
output = BytesIO()
im.save(output, format='JPEG')
im_data = output.getvalue()
result = base64.b64encode(im_data)
except IOError, e:
logger.warning("can't make thumbnail")
except Exception, e:
logger.warning("unexpected exception making thumbnail: "
"(%s)%s" % (type(e), e))
return result


class ImageLoader(threading.Thread):
Expand All @@ -129,7 +137,11 @@ def __init__(self, box, url, *args, **kwargs):
super(ImageLoader, self).__init__(*args, **kwargs)
self.box = box # will hold image or label
self.loader = gtk.gdk.PixbufLoader()
if (url.startswith('http://') or url.startswith('https://')):
self.inline_picture_marker = "|data:image/jpeg;base64,"
if url.find(self.inline_picture_marker) != -1:
self.reader_function = self.read_base64
self.url = url
elif (url.startswith('http://') or url.startswith('https://')):
self.reader_function = self.read_global_url
self.url = url
else:
Expand Down Expand Up @@ -178,6 +190,13 @@ def run(self):
self.url, self.reader_function, on_hit=self.loader.write)
self.loader.close()

def read_base64(self):
self.loader.connect("area-prepared", self.loader_notified)
thumb64pos = self.url.find(self.inline_picture_marker)
offset = thumb64pos + len(self.inline_picture_marker)
import base64
return base64.b64decode(self.url[offset:])

def read_global_url(self):
self.loader.connect("area-prepared", self.loader_notified)
import urllib
Expand Down
100 changes: 25 additions & 75 deletions data/ghini.svg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
14 changes: 14 additions & 0 deletions doc/_static/custom.css
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
h1, h2, h3, h4 {
background-color: #f2f2f2;
border-bottom: 1px solid #ccc;
}

.toggle .admonition-title {
display: block;
clear: both;
Expand All @@ -15,3 +20,12 @@
.toggle .admonition-title.open:after {
content: " ▲";
}

.tight-table td {
white-space: normal !important;
}

p {
margin-bottom: 12px;
}

2 changes: 1 addition & 1 deletion doc/building.rst
Original file line number Diff line number Diff line change
Expand Up @@ -579,7 +579,7 @@ export dialog box. The following command will give you a list of
``GenericEditorView`` instantiations::

grep -nHr -e GenericEditorView\( bauble

Extending Ghini with Plugins
-----------------------------

Expand Down
234 changes: 234 additions & 0 deletions doc/ghini-family.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,234 @@
==================
the Ghini family
==================

Let's start by recalling the composition of the Ghini family, as shown in the diagram:

.. image:: images/ghini-family-clean.png

You have learned how to use ghini.desktop, here we introduce the other
members of the family, and their interaction.

.. _ghini.pocket:

ghini.pocket
============

.. image:: images/ghini-pocket-installed.png
:align: left

ghini.pocket is an Android app which you can install from the `play
store
<https://play.google.com/store/apps/details?id=me.ghini.pocket>`_.
ghini.pocket is definitely the tool you will use most, next to
ghini.desktop.

With ghini.pocket you always have the latest snapshot of your
database with you.

Type an accession number, or scan its barcode or QR label, and you know:

- the identification of the plant,
- whether it already has pictures,
- when it entered the garden and
- from which source.

Apart as a quick data viewer, you can use ghini.pocket for...

.. admonition:: data correction
:class: toggle

If by your judgement, some of the information is incorrect, or if
the plant is flowering and you want to immediately take a picture
and store it in the database, you do not need take notes on paper,
nor follow convolute procedures: ghini.pocket lets you write your
corrections in a log file, take pictures associated to the plant,
and you will import this information straight into the database,
with further minimal user intervention.

.. admonition:: inventory review
:class: toggle

The initial idea on which we based ghini.pocket is still one of its
functionalities: inventory review.

Using ghini.pocket, reviewing the inventory of a greenhouse, in
particular if you have QR codes on plant labels, goes as fast as
you can walk: simply enter the location code of your greenhouse,
reset the log, then one by one scan the plant codes of the plants
in the greenhouse. No further data collection action is required.

When you're done, import the log in ghini.desktop. The procedure
available in ghini.desktop includes adding unknown but labelled
plants in the database, marking as lost/dead all plants that the
database reports as alive and present in the inventoried location,
but were not found during the inventory.

.. admonition:: taxonomic support
:class: toggle

As a bonus, ghini.pocket contains a phonetic genus search, and a
quite complete database of botanic taxa with rank between order and
genus, including tribes, and synonymies.

check further :any:`interaction among components`.

.. _ghini.web:

ghini.web
=========

.. image:: images/ghini-web-installed.png
:align: left

ghini.web is a web server, written in nodejs.

Its most visible part runs at http://gardens.ghini.me and shows as a
map of the world, where you browse gardens and search their published
collection.

It also serves configuration data to ghini.tour instances.

check further :any:`interaction among components`.


.. _ghini.tour:

ghini.tour
==========

.. image:: images/ghini-tour-installed.png
:align: left

ghini.tour is an Android app which you can install from the `play
store
<https://play.google.com/store/apps/details?id=me.ghini.tour>`_.

People visiting your garden will install ghini.tour on their phone or
tablet, enjoy having a map of the garden, knowing where they are, and
will be able to listen to audio files that you have placed as virtual
information panels in strategic spots in your garden.

.. admonition:: world view
:class: toggle

at startup, you see the world and gardens. select a garden, and enter.

.. admonition:: garden view
:class: toggle

when viewing at garden level, you see panels. select a panel, and listen.

check further :any:`interaction among components`.


.. _interaction among components:

data streams between software components
========================================

.. note:: This section contains technical information for database managers and
software developers.

.. image:: images/ghini-streams-installed.png
:align: left

In the diagram showing the composition of the Ghini family, the alert
reader noticed how different arrows representing different data
flows, had different colours: some are deep green, some have a
lighter tint.


Deeper green streams are constant flows of data, representing the core
activity of a component, eg: the interaction between ghini.desktop and its
database server, or your internet browser and ghini.web.

Lighter green streams are import/export actions, initiated by the user at the
command panel of ghini.desktop, or in the ghini.tour settings page.

This is the same graph, in which all import data streams have been given an
identifier.

.. image:: images/ghini-family-streams.png

.. admonition:: d2p: copy a snapshot of the desktop database to ghini.pocket
:class: toggle

- export the desktop database to a pocket snapshot
- copy the snapshot to the handheld device

ghini.pocket integrates closely with ghini.desktop, and it's not a
tool for the casual nor the external user. One task of your garden
database manager is to regularly copy an updated database snapshot to
your Android device.

We advise enabling USB debugging on the device. In perspective, this will
allow ghini.desktop writing directily into the ghini.pocket device.

Export the file from ghini.desktop, call the file pocket.db, copy it to the phone::

adb -d push /tmp/pocket.db /sdcard/Android/data/me.ghini.pocket/files/

The above location is valid even if your phone does not have a memory card.

Other options include bluetooth, or whatever other way you normally use to
copy regular files into your Android device.



.. admonition:: p2d: import from the ghini.pocket log file and pictures into the central database
:class: toggle

even if we're still calling it “inventory log”, ghini.pocket's log
contains more than just inventory corrections.

- produce a log on the handheld device
- import the log in the desktop database

first of all, copy the collected information from ghini.pocket into your computer::

export DIR=/some/directory/on/your/computer
adb -d pull /sdcard/Android/data/me.ghini.pocket/files/searches.txt $DIR
adb -d pull -a /sdcard/Android/data/me.ghini.pocket/files/Pictures $DIR

then use ghini.desktop to import this information into your database.


.. admonition:: d2w: send a selection of your garden data to ghini.web
:class: toggle

Offer a selection of your garden data to a central ghini.web site, so
online virtual visitors can browse it. This includes plant
identification and their geographic location.

content of this flow:

- garden: coords, name, zoom level (for initial view)
- plants: coords, identification, zoom level (for visibility)
- species: binomial, phonetic approximation



.. admonition:: g2w: add geographic non-botanic data to ghini.web
:class: toggle

- Write geographic information about non-botanic data (ie: point of
interest within the garden, required by ghini.tour) in the central
ghini.web site.

content of this flow:

- virtual panels: coords, title, audio file
- photos: coords, title, picture

virtual panels don't necessarily have an associated photo, photos
don't necessarily have an associated audio file.


.. admonition:: w2t: importing locations and POIs from ghini.web to tour
:class: toggle

content of this flow:

- Garden (coords, name, zoom level)
- Points of Interest (coords, title, audio file, photo)
Binary file added doc/images/ghini-family-clean.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added doc/images/ghini-family-streams.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified doc/images/ghini-family.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added doc/images/ghini-pocket-installed.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added doc/images/ghini-streams-installed.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added doc/images/ghini-tour-installed.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added doc/images/ghini-wallpaper.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 415e586

Please sign in to comment.