1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
|
/*********
*
* This file is part of BibleTime's source code, http://www.bibletime.info/.
*
* Copyright 1999-2008 by the BibleTime developers.
* The BibleTime source code is licensed under the GNU General Public License version 2.0.
*
**********/
#include "frontend/bookshelfmanager/installpage/btsourcearea.h"
#include <QString>
#include <QWidget>
#include <QMap>
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QSpacerItem>
#include <QLabel>
#include <QPushButton>
#include <QTreeWidget>
#include <QTreeWidgetItem>
#include <QHeaderView>
#include <QDebug>
#include <QTime>
#include "backend/managers/cswordbackend.h"
#include "frontend/bookshelfmanager/instbackend.h"
#include "frontend/btaboutmoduledialog.h"
#include "util/directory.h"
#include "util/cpointers.h"
#include "util/cresmgr.h"
#include "util/tool.h"
// Sword includes:
#include <installmgr.h>
// ****************************************************************
// ******** Installation source and module list widget ************
// ****************************************************************
BtSourceArea::BtSourceArea(const QString& sourceName)
: QWidget(),
m_sourceName(sourceName),
m_treeAlreadyInitialized(false),
m_remoteBackend(0) { //important!
setObjectName(sourceName);
m_checkedModules = QMap<QString, bool>();
qDebug() << "BtSourceArea::BtSourceArea, " << m_sourceName;
initView();
}
BtSourceArea::~BtSourceArea() {
qDebug() << "BtSourceArea::~BtSourceArea" << m_sourceName;
delete m_remoteBackend;
}
void BtSourceArea::initView() {
namespace DU = util::directory;
qDebug() << "BtSourceArea::initView";
QVBoxLayout *mainLayout = new QVBoxLayout(this);
// source related button row
QHBoxLayout *sourceLayout = new QHBoxLayout();
m_refreshButton = new QPushButton(tr("Refresh..."));
m_refreshButton->setToolTip(tr("Refresh the list of works from this source"));
m_refreshButton->setIcon(DU::getIcon(CResMgr::bookshelfmgr::installpage::refresh_icon));
//m_refreshButton->setEnabled(false);
QSpacerItem *sourceSpacer = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum);
//m_editButton = new QPushButton(tr("Edit..."));
/// \todo after writing the edit widget:
//m_editButton->setEnabled(false);
m_deleteButton = new QPushButton(tr("Delete..."));
m_deleteButton->setToolTip(tr("Delete this source"));
m_deleteButton->setIcon(DU::getIcon(CResMgr::bookshelfmgr::installpage::delete_icon));
//m_deleteButton->setEnabled(false);
m_addButton = new QPushButton(tr("Add..."));
m_addButton->setToolTip(tr("Add new source"));
m_addButton->setIcon(DU::getIcon(CResMgr::bookshelfmgr::installpage::add_icon));
sourceLayout->addWidget(m_refreshButton);
sourceLayout->addItem(sourceSpacer);
//sourceLayout->addWidget(m_editButton);
sourceLayout->addWidget(m_deleteButton);
sourceLayout->addWidget(m_addButton);
mainLayout->addLayout(sourceLayout);
// There are no views for the stack yet, see initSources
m_view = new QTreeWidget(this);
m_view->setHeaderLabels(QStringList() << tr("Work") << tr("Description"));
m_view->setColumnWidth(0, util::tool::mWidth(m_view, 20));
mainLayout->addWidget(m_view);
connect(m_view, SIGNAL(itemDoubleClicked(QTreeWidgetItem*, int)), SLOT(slotItemDoubleClicked(QTreeWidgetItem*, int)));
connect(CPointers::backend(), SIGNAL(sigSwordSetupChanged(CSwordBackend::SetupChangedReason)), SLOT(slotSwordSetupChanged()));
connect(this, SIGNAL(signalCreateTree()), SLOT(slotCreateTree()), Qt::QueuedConnection);
}
void BtSourceArea::prepareRemove() {
// don't create tree anymore, this will be removed
disconnect(this, SIGNAL(signalCreateTree()), this, SLOT(slotCreateTree()));
}
QSize BtSourceArea::sizeHint() const {
return QSize(100, m_refreshButton->height() + (m_view->header()->height() * 5));
}
void BtSourceArea::initTreeFirstTime() {
if (!m_treeAlreadyInitialized) {
createModuleTree();
m_treeAlreadyInitialized = true;
}
}
void BtSourceArea::createModuleTree() {
qDebug() << "BtSourceArea::createModuleTree start";
// Start creating tree with a queued connection.
// This makes showing the dialog possible even before the tree is initialized.
emit signalCreateTree();
}
void BtSourceArea::slotCreateTree() {
qDebug() << "BtSourceArea::slotCreateTree" << QTime::currentTime ();
//let the dialog become visible
QCoreApplication::processEvents();
// Creating the view and populating list may take time
QApplication::setOverrideCursor( QCursor(Qt::WaitCursor) );
// disconnect the signal so that we don't have to run functions for every module
// (note: what to do if we want to restore the item selection when rebuilding?
disconnect(m_view, SIGNAL(itemChanged(QTreeWidgetItem*, int)), this, SLOT(slotSelectionChanged(QTreeWidgetItem*, int)) );
m_view->clear();
/// \todo if the tree already exists for this source, maybe the selections should be preserved
m_checkedModules.clear();
sword::InstallSource is = instbackend::source(m_sourceName);
delete m_remoteBackend; // the old one can be deleted
m_remoteBackend = instbackend::backend(is);
Q_ASSERT(m_remoteBackend);
m_moduleList = m_remoteBackend->moduleList();
// give the list to BTModuleTreeItem, create filter to remove
// those modules which are installed already
InstalledFilter alreadyInstalledFilter(m_sourceName);
QList<BTModuleTreeItem::Filter*> filterList;
filterList.append(&alreadyInstalledFilter);
BTModuleTreeItem rootItem(filterList, BTModuleTreeItem::CatLangMod, &m_moduleList);
addToTree(&rootItem, m_view->invisibleRootItem());
QCoreApplication::processEvents();
// receive signal when user checks modules
connect(m_view, SIGNAL(itemChanged(QTreeWidgetItem*, int)), this, SLOT(slotSelectionChanged(QTreeWidgetItem*, int)) );
QApplication::restoreOverrideCursor();
qDebug() << "BtSourceArea::createModuleTree end" << QTime::currentTime ();
}
void BtSourceArea::addToTree(BTModuleTreeItem* item, QTreeWidgetItem* widgetItem) {
//qDebug()<<"BtSourceArea::addToTree "<<item->text();
//qDebug() << "BTMTItem type: " << item->type();
foreach (BTModuleTreeItem* i, item->children()) {
addToTree(i, new QTreeWidgetItem(widgetItem));
}
if (item->type() != BTModuleTreeItem::Root) {
CSwordModuleInfo* mInfo = item->moduleInfo();
widgetItem->setText(0, item->text());
if (item->type() == BTModuleTreeItem::Category || item->type() == BTModuleTreeItem::Language) {
//qDebug() << "item"<<item->text()<< "was cat or lang";
widgetItem->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsTristate);
}
if (item->type() == BTModuleTreeItem::Module) {
//qDebug() << "item"<<item->text()<< "was a module";
widgetItem->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled);
widgetItem->setCheckState(0, Qt::Unchecked);
CSwordModuleInfo* const installedModule = CPointers::backend()->findModuleByName(mInfo->name());
QString installedV;
if (!installedModule) {
/**
\todo maybe? save the module list of a source before refreshing,
compare after refreshing, mark the newly added modules if
not newly added:
state: installable (no indicator)
else: status: newly added, color yellow
*/
} else { // the module is already installed
QBrush bg(QColor(255, 153, 153)); /// \bug Possible color conflict
widgetItem->setBackground(0, bg);
widgetItem->setBackground(1, bg);
installedV = QString(installedModule->config(CSwordModuleInfo::ModuleVersion).toLatin1());
// set the color for the parent items
QTreeWidgetItem* parent1 = widgetItem->parent();
if (parent1) {
parent1->setBackground(0, bg);
parent1->setBackground(1, bg);
QTreeWidgetItem* parent2 = parent1->parent();
if (parent2) {
parent2->setBackground(0, bg);
parent2->setBackground(1, bg);
}
}
}
QString descr(mInfo->config(CSwordModuleInfo::Description));
QString toolTipText = util::tool::remoteModuleToolTip(mInfo, installedV);
widgetItem->setText(1, descr);
widgetItem->setToolTip(0, toolTipText);
widgetItem->setToolTip(1, toolTipText);
}
}
}
QTreeWidget* BtSourceArea::treeWidget() {
return m_view;
}
// return the selected modules
QMap<QString, bool>* BtSourceArea::selectedModules() {
return &m_checkedModules;
}
// when a module is checked/unchecked
void BtSourceArea::slotSelectionChanged(QTreeWidgetItem* item, int column) {
//qDebug() << "BtSourceArea::slotSelectionChanged";
// modify the internal list of selected (actually checked) modules
// if() leaves groups away
if (!item->childCount() && column == 0) {
foreach (CSwordModuleInfo* module, m_moduleList) {
if (module->name() == item->text(0)) {
if (item->checkState(0) == Qt::Checked) {
qDebug() << module->name() << "was checked";
m_checkedModules.insert(module->name(), true);
}
else {
qDebug() << module->name() << "was unchecked";
m_checkedModules.remove(module->name());
}
emit signalSelectionChanged(m_sourceName, m_checkedModules.count());
break;
}
}
}
}
void BtSourceArea::slotItemDoubleClicked(QTreeWidgetItem* item, int /*column*/) {
CSwordModuleInfo* mInfo = m_remoteBackend->findModuleByName(item->text(0));
if (mInfo) {
BTAboutModuleDialog* dialog = new BTAboutModuleDialog(this, mInfo);
dialog->show();
dialog->raise();
}
}
BtSourceArea::InstalledFilter::InstalledFilter(QString sourceName)
: BTModuleTreeItem::Filter(),
m_source(instbackend::source(sourceName)),
m_swordBackend(instbackend::backend(m_source)) {
// these are set once to optimize away repeated calls
// m_source, m_swordBackend
}
//filter out already installed, not updateable modules
bool BtSourceArea::InstalledFilter::filter(CSwordModuleInfo* mInfo) {
//qDebug() << "BtSourceArea::InstalledFilter::filter, module " << mInfo->name();
CSwordModuleInfo* const installedModule = CPointers::backend()->findModuleByName(mInfo->name());
if (installedModule) {
//qDebug() << "already installed, check if it's an update...";
const sword::SWVersion installedVersion(installedModule->config(CSwordModuleInfo::ModuleVersion).toLatin1());
const sword::SWVersion newVersion(mInfo->config(CSwordModuleInfo::ModuleVersion).toLatin1());
if (installedVersion >= newVersion) {
return false;
}
}
return true;
}
void BtSourceArea::slotSwordSetupChanged() {
createModuleTree();
}
|