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:
parent
9a2fd50642
commit
79d03159f3
29
src/guiQML/__init__.py
Normal file
29
src/guiQML/__init__.py
Normal 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
171
src/guiQML/grampsqml.py
Normal 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
|
77
src/guiQML/qmlwidgets/TextButton.qml
Normal file
77
src/guiQML/qmlwidgets/TextButton.qml
Normal 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 }
|
||||||
|
}
|
||||||
|
}
|
44
src/guiQML/qmlwidgets/TopBar.qml
Normal file
44
src/guiQML/qmlwidgets/TopBar.qml
Normal 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
|
||||||
|
}
|
||||||
|
}
|
66
src/guiQML/questiondialog.py
Normal file
66
src/guiQML/questiondialog.py
Normal 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
156
src/guiQML/viewmanager.py
Normal 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)
|
29
src/guiQML/views/__init__.py
Normal file
29
src/guiQML/views/__init__.py
Normal 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__ = [ ]
|
174
src/guiQML/views/centralview.py
Normal file
174
src/guiQML/views/centralview.py
Normal 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)
|
65
src/guiQML/views/centralview.qml
Normal file
65
src/guiQML/views/centralview.qml
Normal 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
225
src/guiQML/views/dbman.py
Normal 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
200
src/guiQML/views/dbman.qml
Normal 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("")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
66
src/guiQML/views/peopleview.qml
Normal file
66
src/guiQML/views/peopleview.qml
Normal 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
|
||||||
|
}
|
||||||
|
}
|
214
src/guiQML/views/personview.py
Normal file
214
src/guiQML/views/personview.py
Normal 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
|
Loading…
Reference in New Issue
Block a user