Commit experimental QML interface, python gramps.py --qml to run

This is not part of Makefile system at the moment. Just proof of concept to see what can be done


svn: r16505
This commit is contained in:
Benny Malengier 2011-01-30 16:39:28 +00:00
parent 9a2fd50642
commit 79d03159f3
13 changed files with 1516 additions and 0 deletions

29
src/guiQML/__init__.py Normal file
View File

@ -0,0 +1,29 @@
#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2010 Benny Malengier
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
# $Id$
"""
Package init for the guiQML package.
"""
# DO NOT IMPORT METHODS/CLASSES FROM src/guiQML HERE ! Only __all__
__all__ = [ ]

171
src/guiQML/grampsqml.py Normal file
View File

@ -0,0 +1,171 @@
#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2010 Benny Malengier
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
# $Id$
"""
main file to start the QML application
"""
#-------------------------------------------------------------------------
#
# Standard python modules
#
#-------------------------------------------------------------------------
import sys, os
#-------------------------------------------------------------------------
#
# set up logging
#
#-------------------------------------------------------------------------
import logging
LOG = logging.getLogger(".grampsqml")
#-------------------------------------------------------------------------
#
# GRAMPS modules
#
#-------------------------------------------------------------------------
import constfunc
import config
#-------------------------------------------------------------------------
#
# Main Gramps class
#
#-------------------------------------------------------------------------
class GrampsQML(object):
"""
Main class corresponding to a running gramps process.
There can be only one instance of this class per gramps application
process. It may spawn several windows and control several databases.
"""
def __init__(self, argparser):
import DbState
from guiQML.viewmanager import ViewManager
from cli.arghandler import ArgHandler
from PySide import QtGui
self.app = QtGui.QApplication(sys.argv)
dbstate = DbState.DbState()
self.vm = ViewManager(dbstate)
#act based on the given arguments
ah = ArgHandler(dbstate, argparser, self.vm, self.argerrorfunc,
gui=True)
ah.handle_args_gui()
if ah.open or ah.imp_db_path:
# if we opened or imported something, only show the interface
self.vm.post_init_interface()
elif config.get('paths.recent-file') and config.get('behavior.autoload'):
# if we need to autoload last seen file, do so
filename = config.get('paths.recent-file')
if os.path.isdir(filename) and \
os.path.isfile(os.path.join(filename, "name.txt")) and \
ah.check_db(filename):
self.vm.open_activate(filename)
self.vm.post_init_interface()
else:
self.vm.post_init_interface()
else:
# open without fam tree loaded
self.vm.post_init_interface()
#start the QT loop
self.app.exec_()
def argerrorfunc(self, string):
from guiQML.questiondialog import ErrorDialog
""" Show basic errors in argument handling in GUI fashion"""
ErrorDialog(_("Error parsing arguments"), string)
def startqml(errors, argparser):
"""
Main startup function started via gobject.timeout_add
First action inside the gtk loop
"""
from guiQML.questiondialog import ErrorDialog, run_dialog_standalone
#handle first existing errors in GUI fashion
if errors:
run_dialog_standalone(ErrorDialog,errors[0], errors[1])
sys.exit()
if argparser.errors:
run_dialog_standalone(ErrorDialog, argparser.errors[0],
argparser.errors[1])
sys.exit()
# add gui logger
from GrampsLogger import RotateHandler
form = logging.Formatter(fmt="%(relativeCreated)d: %(levelname)s: "
"%(filename)s: line %(lineno)d: %(message)s")
# Create the log handlers
rh = RotateHandler(capacity=20)
rh.setFormatter(form)
# Only error and critical log records should
# trigger the GUI handler.
#qmlh = QMLHandler(rotate_handler=rh)
#qmlh.setFormatter(form)
#qmlh.setLevel(logging.ERROR)
l = logging.getLogger()
l.addHandler(rh)
#l.addHandler(gmlh)
# start GRAMPS, errors stop the gtk loop
try:
quit_now = False
openGL = True
exit_code = 0
if constfunc.has_display():
GrampsQML(argparser)
else:
print("Gramps terminated because of no DISPLAY")
sys.exit(exit_code)
except SystemExit, e:
quit_now = True
if e.code:
exit_code = e.code
LOG.error("Gramps terminated with exit code: %d." \
% e.code, exc_info=True)
except OSError, e:
quit_now = True
exit_code = e[0] or 1
try:
fn = e.filename
except AttributeError:
fn = ""
LOG.error("Gramps terminated because of OS Error\n" +
"Error details: %s %s" % (repr(e), fn), exc_info=True)
except:
quit_now = True
exit_code = 1
LOG.error("Gramps failed to start.", exc_info=True)
if quit_now:
#quit
sys.exit(exit_code)
#function finished, return False to stop the timeout_add function calls
return False

View File

@ -0,0 +1,77 @@
/****************************************************************************
**
** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the examples of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:BSD$
** You may use this file under the terms of the BSD license as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in
** the documentation and/or other materials provided with the
** distribution.
** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
** the names of its contributors may be used to endorse or promote
** products derived from this software without specific prior written
** permission.
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
** $QT_END_LICENSE$
**
****************************************************************************/
import Qt 4.7
Rectangle {
id: container
property alias text: label.text
signal clicked
width: label.width + 20; height: label.height + 6
smooth: true
radius: 10
gradient: Gradient {
GradientStop { id: gradientStop; position: 0.0; color: palette.light }
GradientStop { position: 1.0; color: palette.button }
}
SystemPalette { id: palette }
MouseArea {
id: mouseArea
anchors.fill: parent
onClicked: { container.clicked() }
}
Text {
id: label
anchors.centerIn: parent
}
states: State {
name: "pressed"
when: mouseArea.pressed
PropertyChanges { target: gradientStop; color: palette.dark }
}
}

View File

@ -0,0 +1,44 @@
/*#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2010 Benny Malengier
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
# $Id: __init__.py 13807 2009-12-15 05:56:12Z pez4brian $
*/
import Qt 4.7
Item {
id: titlebar
property alias text: titletext.text
width: parent.width
height: 20
Rectangle {
anchors.fill: parent
color: "#343434"
}
Text {
id: titletext
anchors.horizontalCenter: parent.horizontalCenter
text: text
font.pixelSize: 15
color: "white"
font.bold: true
}
}

View File

@ -0,0 +1,66 @@
#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2010 Benny Malengier
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
# $Id: __init__.py 13807 2009-12-15 05:56:12Z pez4brian
"""
Some often needed dialogs
"""
#-------------------------------------------------------------------------
#
# Standard python modules
#
#-------------------------------------------------------------------------
import sys
#-------------------------------------------------------------------------
#
# QT modules
#
#-------------------------------------------------------------------------
from PySide.QtCore import *
from PySide.QtGui import *
#-------------------------------------------------------------------------
#
# Classes for the Dialogs
#
#-------------------------------------------------------------------------
class ErrorDialog(QDialog):
def __init__(self, msg1, msg2="", parent=None):
super(ErrorDialog, self).__init__(parent)
self.setWindowTitle("%s - Gramps" % msg1)
lbl1 = QLabel(msg1)
lbl2 = QLabel(msg2)
layout = QVBoxLayout()
layout.addWidget(lbl1)
layout.addWidget(lbl2)
# Set dialog layout
self.setLayout(layout)
self.setMinimumSize(350,300)
self.show()
def run_dialog_standalone(dlgclass, *args, **keywords):
app = QApplication(sys.argv)
QObject.connect(app, SIGNAL('lastWindowClosed()'), app, SLOT('quit()'))
win = dlgclass(*args, **keywords)
app.exec_()

156
src/guiQML/viewmanager.py Normal file
View File

@ -0,0 +1,156 @@
#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2010 Benny Malengier
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
# $Id$
"""
The main view
"""
#-------------------------------------------------------------------------
#
# Constants
#
#-------------------------------------------------------------------------
OPENGL = True
#-------------------------------------------------------------------------
#
# Standard python modules
#
#-------------------------------------------------------------------------
import sys, os
#-------------------------------------------------------------------------
#
# set up logging
#
#-------------------------------------------------------------------------
import logging
LOG = logging.getLogger(".")
#-------------------------------------------------------------------------
#
# QT modules
#
#-------------------------------------------------------------------------
from PySide import QtCore
from PySide import QtGui
from PySide import QtDeclarative
from PySide import QtOpenGL
#-------------------------------------------------------------------------
#
# GRAMPS modules
#
#-------------------------------------------------------------------------
import const
from cli.grampscli import CLIManager, CLIDbLoader
from gen.ggettext import gettext as _
from guiQML.views.dbman import DbManager
from guiQML.questiondialog import ErrorDialog
#-------------------------------------------------------------------------
#
# ViewManager
#
#-------------------------------------------------------------------------
class ViewManager(CLIManager):
"""
Manages main widget by holding what state it is in.
"""
def __init__(self, dbstate):
"""
The viewmanager is initialised with a dbstate on which GRAMPS is
working.
"""
self.__centralview = None
CLIManager.__init__(self, dbstate, False)
self.db_loader = CLIDbLoader(self.dbstate)
#there is one DeclarativeEngine for global settings
self.__build_main_window()
def __build_main_window(self):
"""
Builds the QML interface
"""
self.mainwindow = QtGui.QMainWindow()
self.mainview = QtDeclarative.QDeclarativeView()
if OPENGL:
glw = QtOpenGL.QGLWidget()
self.mainview.setViewport(glw)
self.mainview.setResizeMode(QtDeclarative.QDeclarativeView.SizeRootObjectToView)
self.engine = self.mainview.engine()
self.engine.rootContext().setBaseUrl(QtCore.QUrl.fromLocalFile(
os.path.join(const.ROOT_DIR, "guiQML")))
#set up the family tree list to select from
self.dbman = DbManager(self.dbstate, self.engine, self.load_db)
def post_init_interface(self):
"""
Showing the main window is deferred so that
ArgHandler can work without it always shown
"""
if not self.dbstate.db.is_open():
self.__open_dbman(None)
else:
self.__open_centralview(None)
def __open_dbman(self, obj):
"""
Called when the Open button is clicked, opens the DbManager
"""
self.dbman.show(self.mainview, self.mainwindow)
def _errordialog(self, title, errormessage):
"""
Show the error.
In the GUI, the error is shown, and a return happens
"""
ErrorDialog(title, errormessage, parent=self.mainwindow)
return 1
def load_db(self, path):
"""
Load the db and set the interface to the central widget
"""
self.db_loader.read_file(path)
self.__open_centralview(None)
def __open_centralview(self, obj):
"""
set interface to the central widget
"""
if not self.__centralview:
from guiQML.views.centralview import CentralView
self.__centralview = CentralView(self.dbstate, self.engine,
self.open_view)
self.__centralview.show(self.mainview, self.mainwindow)
def open_view(self, viewclass, *args):
"""
set interface to the given view:
"""
##we should destroy views that are double
##we should do some caching of views so as to move quickly?
newview = viewclass(self.dbstate, self.engine, *args)
newview.show(self.mainview, self.mainwindow)

View File

@ -0,0 +1,29 @@
#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2010 Benny Malengier
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
# $Id$
"""
Package init for different views in guiQML.
"""
# DO NOT IMPORT METHODS/CLASSES FROM src/guiQML HERE ! Only __all__
__all__ = [ ]

View File

@ -0,0 +1,174 @@
#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2010 Benny Malengier
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
# $Id$
"""
The main view from where other views are started
"""
#-------------------------------------------------------------------------
#
# Constants
#
#-------------------------------------------------------------------------
#-------------------------------------------------------------------------
#
# Standard python modules
#
#-------------------------------------------------------------------------
import sys, os
#-------------------------------------------------------------------------
#
# set up logging
#
#-------------------------------------------------------------------------
import logging
LOG = logging.getLogger(".")
#-------------------------------------------------------------------------
#
# QT modules
#
#-------------------------------------------------------------------------
from PySide import QtCore
from PySide import QtGui
from PySide import QtDeclarative
from PySide import QtOpenGL
#-------------------------------------------------------------------------
#
# GRAMPS modules
#
#-------------------------------------------------------------------------
import const
from gen.ggettext import gettext as _
#-------------------------------------------------------------------------
#
# Classes
#
#-------------------------------------------------------------------------
class DetailView(QtCore.QObject):
"""
Data known about a detail view that can be launched
"""
def __init__(self, name):
QtCore.QObject.__init__(self)
self.__name = name
def _name(self):
return self.__name
changed = QtCore.Signal()
#make Model.Column.property available in QML
name = QtCore.Property(unicode, _name, notify=changed)
class DetViewSumModel(QtCore.QAbstractListModel):
"""
A simple ListModel for the different detailed views
"""
COLUMNS = ('name', )
def __init__(self, detviews):
QtCore.QAbstractListModel.__init__(self)
self._detviews = detviews
self.setRoleNames(dict(enumerate(DetViewSumModel.COLUMNS)))
def rowCount(self, parent=QtCore.QModelIndex()):
return len(self._detviews)
def data(self, index, role):
print 'role', role, DetViewSumModel.COLUMNS.index('name')
if index.isValid() and role == DetViewSumModel.COLUMNS.index('name'):
return self._detviews[index.row()]
return None
#-------------------------------------------------------------------------
#
# CentralView
#
#-------------------------------------------------------------------------
class CentralView(QtCore.QObject):
"""
Manages family tree list widget
"""
def __init__(self, dbstate, engine, viewshow):
"""
The manager is initialised with a dbstate on which GRAMPS is
working, and the engine to use context from.
"""
self.dbstate = dbstate
self.__viewshow = viewshow
QtCore.QObject.__init__(self)
self.const = {
'titlelabel': unicode("%s" % self.dbstate.db.get_dbname()),
}
print self.const['titlelabel']
#there is one DeclarativeEngine for global settings
self.__build_main_window(engine)
def __build_main_window(self, engine):
"""
Builds the QML interface
"""
parentcontext = engine.rootContext()
#Create a context for the family tree list
self.centralviewcontext = QtDeclarative.QDeclarativeContext(parentcontext)
#Create ListModel to use
detviews = DetViewSumModel([DetailView('People')])
#register them in the context
self.centralviewcontext.setContextProperty('Const', self.const)
self.centralviewcontext.setContextProperty('CentralView', self)
self.centralviewcontext.setContextProperty('DetViewSumModel', detviews)
#create a Component to show
self.centralview = QtDeclarative.QDeclarativeComponent(engine)
self.centralview.loadUrl(QtCore.QUrl.fromLocalFile(
os.path.join(const.ROOT_DIR, "guiQML", 'views', 'centralview.qml')))
#and obtain the QObject of it
self.Qcentralview = self.centralview.create(self.centralviewcontext)
def show(self, graphicsview, mainwindow):
"""
Paint the Component on the View and put it in the given mainwindow.
"""
#scene.addItem(self.Qfamtreeview)
graphicsview.setRootObject(self.Qcentralview)
graphicsview.show();
mainwindow.setCentralWidget(graphicsview)
mainwindow.show()
@QtCore.Slot(QtCore.QObject)
def detviewSelected(self, detview):
"""
We load the selected family tree
"""
print 'User clicked on:', detview.name
#now only Person piece to click on, so start that
from guiQML.views.personview import QMLPersonList
self.__viewshow(QMLPersonList)

View File

@ -0,0 +1,65 @@
/*#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2010 Benny Malengier
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
# $Id: __init__.py 13807 2009-12-15 05:56:12Z pez4brian $
*/
import Qt 4.7
import "../qmlwidgets" as Widgets
Rectangle{
id: container
color: "#343434"
ListView {
id: detviewSumList
y: 25
width: parent.width
height: parent.height-25
model: DetViewSumModel
delegate: Component {
Rectangle {
width: detviewSumList.width
height: 40
color: ((index % 2 == 0)?'#222':'#111')
Text {
id: detviewname
elide: Text.ElideRight
text: model.name.name
color: 'white'
font.bold: true
anchors.leftMargin: 10
anchors.fill: parent
verticalAlignment: Text.AlignVCenter
}
MouseArea {
anchors.fill: parent
onClicked: {
CentralView.detviewSelected(model.name)
}
}
}
}
}
// TOP BAR
Widgets.TopBar {
text: Const.titlelabel
}
}

225
src/guiQML/views/dbman.py Normal file
View File

@ -0,0 +1,225 @@
#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2010 Benny Malengier
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
# $Id$
"""
The main view
"""
#-------------------------------------------------------------------------
#
# Constants
#
#-------------------------------------------------------------------------
OPENGL = True
#-------------------------------------------------------------------------
#
# Standard python modules
#
#-------------------------------------------------------------------------
import sys, os
#-------------------------------------------------------------------------
#
# set up logging
#
#-------------------------------------------------------------------------
import logging
LOG = logging.getLogger(".")
#-------------------------------------------------------------------------
#
# QT modules
#
#-------------------------------------------------------------------------
from PySide import QtCore
from PySide import QtGui
from PySide import QtDeclarative
from PySide import QtOpenGL
#-------------------------------------------------------------------------
#
# GRAMPS modules
#
#-------------------------------------------------------------------------
import const
from cli.clidbman import CLIDbManager, NAME_FILE, time_val
from gen.ggettext import gettext as _
#-------------------------------------------------------------------------
#
# Classes
#
#-------------------------------------------------------------------------
#open_icon = QtGui.QIcon.fromTheme('open')
FAMTREE_ICONPATH = os.path.join(const.IMAGE_DIR, '22x22', 'gramps.png')
class FamTreeWrapper(QtCore.QObject):
"""
A QObject wrapper
"""
def __init__(self, thing, dbman):
QtCore.QObject.__init__(self)
self.__dbman = dbman
self.__name = thing[CLIDbManager.IND_NAME]
self.__path = thing[CLIDbManager.IND_PATH]
self.__path_namefile = thing[CLIDbManager.IND_PATH_NAMEFILE]
self.__last_access = thing[CLIDbManager.IND_TVAL_STR]
self.__use_icon = thing[CLIDbManager.IND_USE_ICON_BOOL]
self.__icon = thing[CLIDbManager.IND_STOCK_ID]
changed = QtCore.Signal()
changed_name = QtCore.Signal()
def _name(self): return self.__name
def _path(self): return self.__path
def _last_access(self): return self.__last_access
def _use_icon(self): return self.__use_icon
def _icon(self): return self.__icon
def _set_name(self, name):
self.__name = name
self.__dbman.rename_database(self.__path_namefile, name)
self.changed_name.emit()
name = QtCore.Property(unicode, _name, _set_name, notify=changed_name)
path = QtCore.Property(unicode, _path, notify=changed)
last_access = QtCore.Property(unicode, _last_access, notify=changed)
use_icon = QtCore.Property(bool, _use_icon, notify=changed)
icon = QtCore.Property(unicode, _icon, notify=changed)
class FamTreeListModel(QtCore.QAbstractListModel):
"""
A simple ListModel
"""
COLUMNS = ('name', 'path', 'last_access', 'use_icon', 'icon')
def __init__(self, famtrees):
QtCore.QAbstractListModel.__init__(self)
self._famtrees = famtrees
self.setRoleNames(dict(enumerate(FamTreeListModel.COLUMNS)))
def rowCount(self, parent=QtCore.QModelIndex()):
return len(self._famtrees)
def data(self, index, role):
if index.isValid() and role == FamTreeListModel.COLUMNS.index('name'):
return self._famtrees[index.row()]
return None
def append_famtree(self, famtree):
"""
Append a FamTreeWrapper to the family tree litsmodel
"""
self.beginInsertRows(QtCore.QModelIndex(), self.rowCount(), self.rowCount())
self._famtrees.append(famtree)
self.endInsertRows()
#-------------------------------------------------------------------------
#
# DbManager
#
#-------------------------------------------------------------------------
class DbManager(CLIDbManager, QtCore.QObject):
"""
Manages family tree list widget
"""
def __init__(self, dbstate, engine, onselectcallback):
"""
The manager is initialised with a dbstate on which GRAMPS is
working, and the engine to use context from.
"""
self.__busy = False
self.__onselect = onselectcallback
QtCore.QObject.__init__(self)
CLIDbManager.__init__(self, dbstate)
#constants needed in the QML
self.const = {
'titlelabel': "Gramps - %s" % _("Family Trees"),
'addbtnlbl': _("Add a Family Tree"),
'famtreeicon': FAMTREE_ICONPATH
}
#there is one DeclarativeEngine for global settings
self.__build_main_window(engine)
def __build_main_window(self, engine):
"""
Builds the QML interface
"""
parentcontext = engine.rootContext()
#Create a context for the family tree list
self.famtreecontext = QtDeclarative.QDeclarativeContext(parentcontext)
#Create ListModel to use
famtreesQT = [FamTreeWrapper(obj, self) for obj in self.current_names]
self.famtrees = FamTreeListModel(famtreesQT)
#register them in the context
self.famtreecontext.setContextProperty('Const', self.const)
self.famtreecontext.setContextProperty('DbManager', self)
self.famtreecontext.setContextProperty('FamTreeListModel', self.famtrees)
#create a Component to show
self.famtreeview = QtDeclarative.QDeclarativeComponent(engine)
self.famtreeview.loadUrl(QtCore.QUrl.fromLocalFile(
os.path.join(const.ROOT_DIR, "guiQML", 'views', 'dbman.qml')))
#and obtain the QObject of it
self.Qfamtreeview = self.famtreeview.create(self.famtreecontext)
def show(self, graphicsview, mainwindow):
"""
Paint the Component on the View and put it in the given mainwindow.
"""
#scene.addItem(self.Qfamtreeview)
graphicsview.setRootObject(self.Qfamtreeview)
graphicsview.show();
mainwindow.setCentralWidget(graphicsview)
mainwindow.show()
@QtCore.Slot(QtCore.QObject)
def famtreeSelected(self, wrapper):
"""
We load the selected family tree
"""
if self.__busy:
return
self.__busy = True
self.__onselect(wrapper._path())
self.__busy = False
@QtCore.Slot(QtCore.QObject)
def addfamtree(self, _):
"""
We add a family tree
"""
if self.__busy:
return
self.__busy = True
print 'User clicked on:', 'add fam tree'
new_path, title = self.create_new_db_cli(None)
path_name = os.path.join(new_path, NAME_FILE)
(tval, last) = time_val(new_path)
self.famtrees.append_famtree(FamTreeWrapper([title, new_path, path_name,
last, tval, False, '']))
self.__busy = False

200
src/guiQML/views/dbman.qml Normal file
View File

@ -0,0 +1,200 @@
/*#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2010 Benny Malengier
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
# $Id: __init__.py 13807 2009-12-15 05:56:12Z pez4brian $
*/
import Qt 4.7
import "../qmlwidgets" as Widgets
Rectangle{
id: container
color: "#343434"
width: 400
height: 600
//Delegate for a famtree entry. Two modes:
// 1. List mode (default): shows just the name and allows selection
// 2. Details mode: show extra information
Component {
id: famtreeDelegate
Item {
id: famtree
// Create a property to contain the visibility of the details.
// We bind multiple element's opacity to this one property,
property real detailsOpacity : 0
width: pythonList.width
height: 30
Rectangle {
id: background
anchors.fill: parent
color: ((index % 2 == 0)?'#222':'#111')
radius: 5 //rounded corners
}
//click shows details, close button must be clicked to go back to normal
MouseArea {
anchors.fill: parent
onClicked: {
famtree.state = 'Details'
}
}
//Now the data on the background, detailsOpacity for what to see
Row{
id: topfamtreelayout
width: parent.width
anchors.verticalCenter: parent.verticalCenter
x:10
spacing:10
Column {
id: innerfamtreecol
width: parent.width - 70;
spacing: 5
Text {
id: title
text: model.name.name
color: 'white'
font.bold: true
opacity: (famtree.detailsOpacity ? 0 : 1 )
}
Item {
id: titleEdit
height: 20
width: parent.width
opacity: famtree.detailsOpacity
TextInput {
id: titleinput
text: model.name.name
anchors.fill: parent.fill
color: 'white'
cursorVisible: true; font.bold: true
}
Keys.forwardTo: [(returnKey), (titleinput)]
Item {
id: returnKey
Keys.onReturnPressed: model.name.name = titleinput.text
Keys.onEnterPressed: model.name.name = titleinput.text
Keys.onEscapePressed: titleinput.text = model.name.name
}
}
Text {
id: lastaccess
elide: Text.ElideRight
text: model.name.last_access
color: 'white'
font.bold: true
opacity: famtree.detailsOpacity
}
}
Image {
id:famtreeimage
anchors.verticalCenter: topfamtreelayout.verticalCenter
width: 22; height: 22
anchors.rightMargin: 20
source: Const.famtreeicon
opacity: famtree.detailsOpacity
}
}
Row{
id: buttonfamtreelayout
anchors.top: topfamtreelayout.bottom
anchors.rightMargin: 20
spacing: 20
// A button to select the famtree
Widgets.TextButton {
y: 10
opacity: famtree.detailsOpacity
text: "Open"
onClicked: {
DbManager.famtreeSelected(model.name)
}
}// A button to close the detailed view, i.e. set the state back to default ('').
Widgets.TextButton {
y: 10
opacity: famtree.detailsOpacity
text: "Close"
onClicked: famtree.state = '';
}
}
states: State {
name: "Details"
PropertyChanges { target: famtree; detailsOpacity: 1; x: 0 } // Make details visible
PropertyChanges { target: famtree; height: 120 } // Fill the entire list area with the detailed view
// Move the list so that this item is at the top.
PropertyChanges { target: famtree.ListView.view; explicit: true; contentY: famtree.y }
// Disallow flicking while in in detailed view
PropertyChanges { target: famtree.ListView.view; interactive: false }
}
transitions: Transition {
// Make the state changes smooth
ParallelAnimation {
ColorAnimation { property: "color"; duration: 500 }
NumberAnimation { duration: 300; properties: "detailsOpacity,x,contentY,height,width" }
}
}
}
}
ListView {
id: pythonList
y: 25
width: parent.width
height: parent.height-20-40
//anchors.top: container.top
//anchors.bottom: container.bottom
//anchors.fill: parent
//anchors.leftMargin: 5
//anchors.rightMargin: 5
model: FamTreeListModel
delegate: famtreeDelegate
}
// TOP BAR
Widgets.TopBar {
text: Const.titlelabel
}
// BOTTOM BAR
Item {
id: bottombar
y: parent.height-40
width: parent.width
height: 40
Rectangle {
anchors.fill: parent
color: "#343434"
}
Row {
anchors.left: parent.left
anchors.leftMargin: 10
anchors.verticalCenter: parent.verticalCenter
spacing: 10
Widgets.TextButton {
text: Const.addbtnlbl
onClicked: {DbManager.addfamtree("")
}
}
}
}
}

View File

@ -0,0 +1,66 @@
/*#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2010 Benny Malengier
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
# $Id: __init__.py 13807 2009-12-15 05:56:12Z pez4brian $
*/
import Qt 4.7
import "../qmlwidgets" as Widgets
Rectangle{
id: container
color: "#343434"
ListView {
id: personlist
y: 25
width: parent.width
height: parent.height-25
model: QMLPersonListModel
delegate: Component {
Rectangle {
width: personlist.width
height: 40
radius: 10
color: ((index % 2 == 0)?'#222':'#111')
Text {
id: personname
elide: Text.ElideRight
text: model.name.name
color: 'white'
font.bold: true
anchors.leftMargin: 15
anchors.fill: parent
verticalAlignment: Text.AlignVCenter
}
MouseArea {
anchors.fill: parent
onClicked: {
QMLPersonList.detailsSelected(model.name)
}
}
}
}
}
// TOP BAR
Widgets.TopBar {
text: Const.titlelabel
}
}

View File

@ -0,0 +1,214 @@
#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2010 Benny Malengier
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
# $Id$
"""
The listview with all people in the database
"""
#-------------------------------------------------------------------------
#
# Standard python modules
#
#-------------------------------------------------------------------------
import sys, os
#-------------------------------------------------------------------------
#
# set up logging
#
#-------------------------------------------------------------------------
import logging
LOG = logging.getLogger(".")
#-------------------------------------------------------------------------
#
# QT modules
#
#-------------------------------------------------------------------------
from PySide import QtCore
from PySide import QtGui
from PySide import QtDeclarative
from PySide import QtOpenGL
#-------------------------------------------------------------------------
#
# GRAMPS modules
#
#-------------------------------------------------------------------------
import const
from Utils import conv_unicode_tosrtkey_ongtk
from gen.ggettext import gettext as _
from gen.display.name import displayer as name_displayer
from gen.lib import Name
##TODO: follow must be refractored so as not to require GTK
from gui.views.treemodels.flatbasemodel import FlatNodeMap
#-------------------------------------------------------------------------
#
# Classes
#
#-------------------------------------------------------------------------
## Copied from gui/views/models/peoplemodel, we need a GTK independent base!
COLUMN_NAME = 3
class QMLPerson(QtCore.QObject):
"""
Person object encapsulated for QML
We only store handle and ref to database, obtain data from db as needed
"""
def __init__(self, db, personhandle):
QtCore.QObject.__init__(self)
self.__handle = personhandle
self.__db = db
def _name(self):
return name_displayer.display(self.__db.get_person_from_handle(self.__handle))
#dummy signal for things that change must not be tracked
dummychanged = QtCore.Signal()
#make Model.Column.property available in QML
name = QtCore.Property(unicode, _name, notify=dummychanged)
class QMLPersonListModel(QtCore.QAbstractListModel):
"""
A simple ListModel for the People in the database
"""
ROLE_NAME_COL = 0
COLUMNS = ((ROLE_NAME_COL, 'name'), )
def __init__(self, db):
QtCore.QAbstractListModel.__init__(self)
self.__db = db
self.gen_cursor = db.get_person_cursor
self.sort_func = self.sort_name
self.node_map = FlatNodeMap()
self._reverse = False
#build node map with all peopls
allkeys = self.sort_keys()
ident = True
dlist = allkeys
self.node_map.set_path_map(dlist, allkeys, identical=ident,
reverse=self._reverse)
#every column has a role from 0 to nrcol-1, and name as in COLUMNS
self.setRoleNames(dict(QMLPersonListModel.COLUMNS))
#we create an array with all the QMLPerson that we need so
#that we can match a rowindex with correct QMLPerson
self._qmlpersons = []
for _, handle in self.node_map.full_srtkey_hndl_map():
self._qmlpersons.append(QMLPerson(self.__db, handle))
def sort_keys(self):
"""
Return the (sort_key, handle) list of all data that can maximally
be shown.
This list is sorted ascending, via localized string sort.
conv_unicode_tosrtkey_ongtk which uses strxfrm, which is apparently
broken in Win ?? --> they should fix base lib, we need strxfrm, fix it
in the Utils module.
"""
# use cursor as a context manager
with self.gen_cursor() as cursor:
#loop over database and store the sort field, and the handle
return sorted((map(conv_unicode_tosrtkey_ongtk,
self.sort_func(data)), key) for key, data in cursor)
def sort_name(self, data):
n = Name()
n.unserialize(data[COLUMN_NAME])
return (n.get_primary_surname().get_surname(), n.get_first_name())
def rowCount(self, parent=QtCore.QModelIndex()):
return self.__db.get_number_of_people()
def data(self, index, role):
"""
Obtain QMLPerson to show. Role is a number that corresponds to a column,
different columns can obtain data from different objects
"""
if index.isValid() and role <= QMLPersonListModel.ROLE_NAME_COL:
return self._qmlpersons[index.row()]
return None
#-------------------------------------------------------------------------
#
# CentralView
#
#-------------------------------------------------------------------------
class QMLPersonList(QtCore.QObject):
"""
Manages family tree list widget
"""
def __init__(self, dbstate, engine):
"""
The manager is initialised with a dbstate on which GRAMPS is
working, and the engine to use context from.
"""
self.dbstate = dbstate
QtCore.QObject.__init__(self)
self.const = {
'titlelabel': "%s" % self.dbstate.db.get_dbname(),
}
#there is one DeclarativeEngine for global settings
self.__build_main_window(engine)
def __build_main_window(self, engine):
"""
Builds the QML interface
"""
parentcontext = engine.rootContext()
#Create a context for the family tree list
self.qmlpersonlistcontext = QtDeclarative.QDeclarativeContext(parentcontext)
#Create ListModel to use
personlistmodel = QMLPersonListModel(self.dbstate.db)
#register them in the context
self.qmlpersonlistcontext.setContextProperty('Const', self.const)
self.qmlpersonlistcontext.setContextProperty('QMLPersonList', self)
self.qmlpersonlistcontext.setContextProperty('QMLPersonListModel', personlistmodel)
#create a Component to show
self.qmlpersonlist = QtDeclarative.QDeclarativeComponent(engine)
self.qmlpersonlist.loadUrl(QtCore.QUrl.fromLocalFile(
os.path.join(const.ROOT_DIR, "guiQML", 'views', 'peopleview.qml')))
#and obtain the QObject of it
self.Qpersonlist = self.qmlpersonlist.create(self.qmlpersonlistcontext)
def show(self, graphicsview, mainwindow):
"""
Paint the Component on the View and put it in the given mainwindow.
"""
#scene.addItem(self.Qfamtreeview)
graphicsview.setRootObject(self.Qpersonlist)
graphicsview.show();
mainwindow.setCentralWidget(graphicsview)
mainwindow.show()
@QtCore.Slot(QtCore.QObject)
def detailsSelected(self, qmlperson):
"""
We load the selected family tree
"""
print 'User clicked on:', qmlperson.name