1 /***************************************************************************
2                           rktextmatrix  -  description
3                              -------------------
4     begin                : Thu Nov 08 2007
5     copyright            : (C) 2007, 2010, 2012 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 
18 #include "rktextmatrix.h"
19 
20 #include <QApplication>
21 #include <QClipboard>
22 #include <QMimeData>
23 
24 #include "../debug.h"
25 
RKTextMatrix()26 RKTextMatrix::RKTextMatrix () {
27 	RK_TRACE (EDITOR);
28 
29 	clear ();
30 }
31 
RKTextMatrix(const RKTextMatrix & copy)32 RKTextMatrix::RKTextMatrix (const RKTextMatrix& copy) {
33 	RK_TRACE (EDITOR);
34 
35 	colcount = copy.colcount;
36 	rows = copy.rows;
37 }
38 
~RKTextMatrix()39 RKTextMatrix::~RKTextMatrix () {
40 	RK_TRACE (EDITOR);
41 }
42 
43 // static
matrixFromClipboard()44 RKTextMatrix RKTextMatrix::matrixFromClipboard () {
45 	RK_TRACE (EDITOR);
46 
47 	const QMimeData* data = QApplication::clipboard ()->mimeData ();
48 	// actually, we don't care, whether tsv or plain gets pasted - it's both
49 	// treated the same. We should however encourage external senders to
50 	// provided the two in order.
51 	if (data->hasFormat ("text/tab-separated-values")) {
52 		RK_DEBUG (EDITOR, DL_DEBUG, "paste tsv");
53 		return (matrixFromSeparatedValues (QString::fromLocal8Bit (data->data ("text/tab-separated-values"))));
54 	} else if (data->hasText ()) {
55 		RK_DEBUG (EDITOR, DL_DEBUG, "paste plain text");
56 		return (matrixFromSeparatedValues (data->text ()));
57 	}
58 
59 	return RKTextMatrix ();
60 }
61 
62 // static
matrixFromSeparatedValues(const QString & text,const QRegExp & tab,const QChar & brk)63 RKTextMatrix RKTextMatrix::matrixFromSeparatedValues (const QString& text, const QRegExp& tab, const QChar& brk) {
64 	RK_TRACE (EDITOR);
65 
66 	RKTextMatrix ret;
67 	if (text.isEmpty ()) return ret;
68 
69 	QStringList textrows = text.split (brk);
70 	if (textrows.last ().isEmpty ()) textrows.removeLast ();	// some apps append a trailing line break
71 	for (int i = 0; i < textrows.size (); ++i) {
72 		QStringList split = textrows[i].split (tab);
73 		ret.appendRow (split);
74 	}
75 
76 	return ret;
77 }
78 
toTabSeparatedValues() const79 QString RKTextMatrix::toTabSeparatedValues () const {
80 	RK_TRACE (EDITOR);
81 
82 	QString ret;
83 	for (int row = 0; row < rows.size (); ++row) {
84 		if (row) ret.append ('\n');
85 		ret.append (rows[row].join (QChar ('\t')));
86 	}
87 	return ret;
88 }
89 
copyToClipboard() const90 void RKTextMatrix::copyToClipboard () const {
91 	RK_TRACE (EDITOR);
92 
93 	QString text = toTabSeparatedValues ();
94 	QMimeData* data = new QMimeData ();
95 	data->setText (text);
96 	data->setData ("text/tab-separated-values", text.toLocal8Bit ());
97 	QApplication::clipboard()->setMimeData (data);
98 }
99 
transformed(bool reverse_h,bool reverse_v,bool transpose) const100 RKTextMatrix RKTextMatrix::transformed (bool reverse_h, bool reverse_v, bool transpose) const {
101 	RK_TRACE (EDITOR);
102 
103 	RKTextMatrix ret;
104 	if (isEmpty ()) return ret;		// empty matrices would violate some assumptions of the following code
105 
106 	const int maxrow = rows.size () - 1;		// for easier typing
107 	const int maxcol = rows[0].size () - 1;
108 
109 	if (transpose) ret.upsize (maxcol, maxrow);		// set dimensions from the start to save a few cycles
110 	else ret.upsize (maxrow, maxcol);
111 
112 	for (int row=0; row <= maxrow; ++row) {
113 		for (int col=0; col <= maxcol; ++col) {
114 			int dest_row = row;
115 			if (reverse_v) dest_row = maxrow - row;
116 			int dest_col = col;
117 			if (reverse_h) dest_col = maxcol - col;
118 
119 			if (transpose) {
120 				int dummy = dest_row;
121 				dest_row = dest_col;
122 				dest_col = dummy;
123 			}
124 
125 			ret.setText (dest_row, dest_col, rows[row][col]);
126 		}
127 	}
128 
129 	return ret;
130 }
131 
setText(int row,int col,const QString & text)132 void RKTextMatrix::setText (int row, int col, const QString& text) {
133 //	RK_TRACE (EDITOR);
134 
135 	upsize (row, col);
136 	rows[row][col] = text;
137 }
138 
setColumn(int column,const QString * textarray,int length)139 void RKTextMatrix::setColumn (int column, const QString* textarray, int length) {
140 	RK_TRACE (EDITOR);
141 
142 	upsize (length - 1, column);
143 	for (int i = 0; i < length; ++i) {
144 		rows[i][column] = textarray[i];
145 	}
146 }
147 
appendRow(const QStringList & row)148 void RKTextMatrix::appendRow (const QStringList& row) {
149 	RK_TRACE (EDITOR);
150 
151 	QStringList _row = row;
152 	while (colcount > _row.size ()) _row.append (QString ());
153 	rows.append (_row);
154 	upsize (rows.size ()-1, row.size ()-1);
155 }
156 
getText(int row,int col) const157 QString RKTextMatrix::getText (int row, int col) const {
158 //	RK_TRACE (EDITOR);
159 
160 	if (row > rows.size ()) return QString ();
161 	if (col > colcount) return QString ();
162 	return (rows[row][col]);
163 }
164 
getColumn(int col) const165 QStringList RKTextMatrix::getColumn (int col) const {
166 	RK_TRACE (EDITOR);
167 
168 	if (col > colcount) {
169 		return QStringList ();
170 	}
171 
172 	QStringList ret;
173 	ret.reserve (rows.size ());
174 	for (int i = 0; i < rows.size (); ++i) {
175 		ret.append (rows[i][col]);
176 	}
177 	return ret;
178 }
179 
getRow(int row) const180 QStringList RKTextMatrix::getRow (int row) const {
181 	RK_TRACE (EDITOR);
182 
183 	if (row >= rows.size ()) return (QStringList ());
184 	RK_ASSERT (rows[row].size () == colcount);
185 	return (rows[row]);
186 }
187 
clear()188 void RKTextMatrix::clear () {
189 	RK_TRACE (EDITOR);
190 
191 	rows.clear ();
192 	colcount = 0;
193 }
194 
isEmpty() const195 bool RKTextMatrix::isEmpty () const {
196 	RK_TRACE (EDITOR);
197 
198 	if (rows.isEmpty() || (colcount == 0)) return true;
199 	return false;
200 }
201 
upsize(int newmaxrow,int newmaxcol)202 void RKTextMatrix::upsize (int newmaxrow, int newmaxcol) {
203 //	RK_TRACE (EDITOR);
204 
205 	while (newmaxrow >= rows.size ()) {
206 		QStringList list;
207 		for (int i = 0; i < colcount; ++i) list.append (QString ());
208 		rows.append(list);
209 	}
210 
211 	if (newmaxcol >= colcount) {
212 		for (int i = 0; i < rows.size (); ++i) {
213 			while (newmaxcol >= rows[i].size ()) rows[i].append (QString());
214 		}
215 		colcount = newmaxcol + 1;
216 	}
217 }
218