1 /***************************************************************************
2                           editlabelsdialog  -  description
3                              -------------------
4     begin                : Tue Sep 21 2004
5     copyright            : (C) 2004, 2006, 2007 by Thomas Friedrichsmeier
6     email                : thomas.friedrichsmeier@kdemail.net
7  ***************************************************************************/
8 
9 /***************************************************************************
10  *                                                                         *
11  *   This program is free software; you can redistribute it and/or modify  *
12  *   it under the terms of the GNU General Public License as published by  *
13  *   the Free Software Foundation; either version 2 of the License, or     *
14  *   (at your option) any later version.                                   *
15  *                                                                         *
16  ***************************************************************************/
17 #include "editlabelsdialog.h"
18 
19 #include <KLocalizedString>
20 #include <kactioncollection.h>
21 
22 #include <qlabel.h>
23 #include <QHeaderView>
24 #include <QTimer>
25 #include <QHBoxLayout>
26 #include <QVBoxLayout>
27 #include <QAction>
28 #include <QDialogButtonBox>
29 #include <QPushButton>
30 
31 #include "../core/rkvariable.h"
32 #include "../dataeditor/rktextmatrix.h"
33 #include "../misc/rkdialogbuttonbox.h"
34 #include "celleditor.h"
35 
36 #include "../debug.h"
37 
RKVarLevelsTable(QWidget * parent,const RObject::ValueLabels & labels)38 RKVarLevelsTable::RKVarLevelsTable (QWidget *parent, const RObject::ValueLabels& labels) : RKTableView (parent) {
39 	RK_TRACE (EDITOR);
40 
41 	setHorizontalScrollBarPolicy (Qt::ScrollBarAlwaysOff);
42 	setSelectionMode (QAbstractItemView::ContiguousSelection);
43 	horizontalHeader ()->setStretchLastSection (true);
44 	verticalHeader ()->setFixedWidth (40);
45 	setMinimumWidth (80);
46 
47 	addAction (KStandardAction::cut (this, SLOT (cut()), this));
48 	addAction (KStandardAction::copy (this, SLOT (copy()), this));
49 	addAction (KStandardAction::paste (this, SLOT (paste()), this));
50 	setContextMenuPolicy (Qt::ActionsContextMenu);
51 
52 	setModel (lmodel = new RKVarLevelsTableModel (labels, this));
53 	connect (this, &RKVarLevelsTable::blankSelectionRequest, this, &RKVarLevelsTable::blankSelected);
54 	setRKItemDelegate (new RKItemDelegate (this, lmodel, true));
55 	trailing_rows = 1;
56 }
57 
~RKVarLevelsTable()58 RKVarLevelsTable::~RKVarLevelsTable () {
59 	RK_TRACE (EDITOR);
60 }
61 
blankSelected()62 void RKVarLevelsTable::blankSelected () {
63 	RK_TRACE (EDITOR);
64 
65 	QItemSelectionRange range = getSelectionBoundaries ();
66 	if (!range.isValid ()) return;
67 
68 	for (int row = range.top (); row <= range.bottom (); ++row) {
69 		lmodel->setData (lmodel->index (row, 0), QString ());
70 	}
71 }
72 
cut()73 void RKVarLevelsTable::cut () {
74 	RK_TRACE (EDITOR);
75 
76 	QItemSelectionRange range = getSelectionBoundaries ();
77 	if (!range.isValid ()) return;
78 
79 	copy ();
80 	blankSelected ();
81 }
82 
copy()83 void RKVarLevelsTable::copy () {
84 	RK_TRACE (EDITOR);
85 
86 	QItemSelectionRange range = getSelectionBoundaries ();
87 	if (!range.isValid ()) return;
88 
89 	RKTextMatrix mat;
90 	int trow = 0;
91 	for (int i = range.top (); i <= range.bottom (); ++i) {
92 		mat.setText (trow++, 0, lmodel->data (lmodel->index (i, 0)).toString ());
93 	}
94 	mat.copyToClipboard ();
95 }
96 
paste()97 void RKVarLevelsTable::paste () {
98 	RK_TRACE (EDITOR);
99 
100 // Unfortunately, we need to duplicate some of TwinTable::paste () and RKEditorDataFramPart::doPaste. Those are not easy to reconcile.
101 	QModelIndex current = currentIndex ();
102 	if (!current.isValid ()) return;
103 	int row = current.row ();
104 	RK_ASSERT (current.column () == 0);
105 
106 	RKTextMatrix pasted = RKTextMatrix::matrixFromClipboard ();
107 	if (pasted.isEmpty ()) return;
108 
109 	if (pasted.numColumns () > 1) {		// there were tabs in the pasted text. Let's transpose the first row
110 		for (int i = 0; i < pasted.numColumns (); ++i) {
111 			lmodel->setData (lmodel->index (row++, 0), pasted.getText (0, i));
112 		}
113 	} else {		// else paste the first column
114 		for (int i = 0; i < pasted.numRows (); ++i) {
115 			lmodel->setData (lmodel->index (row++, 0), pasted.getText (i, 0));
116 		}
117 	}
118 }
119 
120 /////////////// RKVarLevelsTableModel /////////////////
121 
RKVarLevelsTableModel(const RObject::ValueLabels & labels,QObject * parent)122 RKVarLevelsTableModel::RKVarLevelsTableModel (const RObject::ValueLabels& labels, QObject* parent) : QAbstractTableModel (parent) {
123 	RK_TRACE (EDITOR);
124 
125 	RKVarLevelsTableModel::labels = labels;
126 }
127 
~RKVarLevelsTableModel()128 RKVarLevelsTableModel::~RKVarLevelsTableModel () {
129 	RK_TRACE (EDITOR);
130 }
131 
rowCount(const QModelIndex & parent) const132 int RKVarLevelsTableModel::rowCount (const QModelIndex& parent) const {
133 	RK_TRACE (EDITOR);
134 
135 	if (parent.isValid ()) return 0;
136 	return labels.count () + 1;
137 }
138 
columnCount(const QModelIndex & parent) const139 int RKVarLevelsTableModel::columnCount (const QModelIndex& parent) const {
140 	RK_TRACE (EDITOR);
141 
142 	if (parent.isValid ()) return 0;
143 	return 1;
144 }
145 
data(const QModelIndex & index,int role) const146 QVariant RKVarLevelsTableModel::data (const QModelIndex& index, int role) const {
147 	RK_TRACE (EDITOR);
148 
149 	if (!index.isValid ()) return QVariant ();
150 	if (index.column () != 0) return QVariant ();
151 	if ((role == Qt::BackgroundRole) && (index.row () == labels.count ())) return QBrush (Qt::gray);
152 	if (index.row () >= labels.count ()) return QVariant ();
153 
154 	if ((role == Qt::DisplayRole) || (role == Qt::EditRole)) return labels.value (QString::number (index.row ()+1));
155 
156 	return QVariant ();
157 }
158 
flags(const QModelIndex & index) const159 Qt::ItemFlags RKVarLevelsTableModel::flags (const QModelIndex& index) const {
160 	RK_TRACE (EDITOR);
161 
162 	if (!index.isValid ()) return 0;
163 	if (index.column () != 0) return 0;
164 	if (index.row () >= labels.count ()) return (Qt::ItemIsEditable | Qt::ItemIsEnabled);
165 	return (Qt::ItemIsEditable | Qt::ItemIsEnabled | Qt::ItemIsSelectable);
166 }
167 
setData(const QModelIndex & index,const QVariant & value,int role)168 bool RKVarLevelsTableModel::setData (const QModelIndex& index, const QVariant& value, int role) {
169 	RK_TRACE (EDITOR);
170 
171 	if (role != Qt::EditRole) return false;
172 	if (!index.isValid ()) return false;
173 	if (index.column () != 0) return false;
174 	if (!value.isValid ()) return false;
175 	if (index.row () > labels.count ()) return false;
176 
177 	QString text = value.toString ();
178 	if (index.row () == labels.count ()) {
179 		beginInsertRows (QModelIndex (), index.row (), index.row ());
180 		labels.insert (QString::number (index.row () + 1), text);
181 		endInsertRows ();
182 	} else {
183 		labels.insert (QString::number (index.row () + 1), text);
184 		emit (dataChanged (index, index));
185 	}
186 
187 	if (text.isEmpty ()) {	// remove trailing empty rows
188 		while ((!labels.isEmpty ()) && labels.value (QString::number (labels.count ())).isEmpty ()) {
189 			int row = labels.count () - 1;
190 			beginRemoveRows (QModelIndex (), row, row);
191 			labels.remove (QString::number (row + 1));
192 			endRemoveRows ();
193 		}
194 	}
195 
196 	return true;
197 }
198 
headerData(int section,Qt::Orientation orientation,int role) const199 QVariant RKVarLevelsTableModel::headerData (int section, Qt::Orientation orientation, int role) const {
200 	RK_TRACE (EDITOR);
201 
202 	if (role != Qt::DisplayRole) return QVariant ();
203 	if (orientation == Qt::Vertical) return QString::number (section + 1);
204 	if (section != 0) return QVariant ();
205 	return i18n ("Label");
206 }
207 
208 //////////////// EditLabelsDialog ///////////////////////
209 
EditLabelsDialog(QWidget * parent,const RObject::ValueLabels & labels,const QString & varname)210 EditLabelsDialog::EditLabelsDialog (QWidget *parent, const RObject::ValueLabels& labels, const QString& varname) : QDialog (parent) {
211 	RK_TRACE (EDITOR);
212 
213 	setWindowTitle (i18n ("Levels / Value labels for '%1'", varname));
214 
215 	QVBoxLayout *layout = new QVBoxLayout (this);
216 	QLabel *label = new QLabel (i18n ("Levels can be assigned only to consecutive integers starting with 1 (the index column is read only). To remove levels at the end of the list, just set them to empty."), this);
217 	label->setWordWrap (true);
218 	layout->addWidget (label);
219 
220 	table = new RKVarLevelsTable (this, labels);
221 	layout->addWidget (table);
222 
223 	RKDialogButtonBox *buttons = new RKDialogButtonBox (QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this);
224 	layout->addWidget (buttons);
225 }
226 
~EditLabelsDialog()227 EditLabelsDialog::~EditLabelsDialog () {
228 	RK_TRACE (EDITOR);
229 }
230 
accept()231 void EditLabelsDialog::accept () {
232 	RK_TRACE (EDITOR);
233 
234 	table->setCurrentIndex (QModelIndex ());	// should flush editing
235 	QDialog::accept ();
236 }
237 
238 ////////////////// EditLabelsDialogProxy /////////////////////////
239 
EditLabelsDialogProxy(QWidget * parent)240 EditLabelsDialogProxy::EditLabelsDialogProxy (QWidget* parent) : QWidget (parent) {
241 	RK_TRACE (EDITOR);
242 	dialog = 0;
243 }
244 
~EditLabelsDialogProxy()245 EditLabelsDialogProxy::~EditLabelsDialogProxy () {
246 	RK_TRACE (EDITOR);
247 }
248 
initialize(const RObject::ValueLabels & labels,const QString & varname)249 void EditLabelsDialogProxy::initialize (const RObject::ValueLabels& labels, const QString& varname) {
250 	RK_TRACE (EDITOR);
251 
252 	if (dialog) return;	// one dialog at a time, please!
253 
254 	EditLabelsDialogProxy::labels = labels;		// we need to take a copy in case the dialog is rejected
255 
256 	dialog = new EditLabelsDialog (this, labels, varname);
257 	connect (dialog, &QDialog::finished, this, &EditLabelsDialogProxy::dialogDone);
258 	QTimer::singleShot (0, dialog, SLOT (exec()));
259 }
260 
dialogDone(int result)261 void EditLabelsDialogProxy::dialogDone (int result) {
262 	RK_TRACE (EDITOR);
263 	RK_ASSERT (dialog);
264 
265 	if (result == QDialog::Accepted) {
266 		labels = dialog->table->lmodel->labels;
267 		emit (done (this, RKItemDelegate::EditorExit));
268 	} else {
269 		emit (done (this, RKItemDelegate::EditorReject));
270 	}
271 	dialog->deleteLater ();
272 	dialog = 0;
273 }
274 
275 
276