1
/***************************************************************************
2
* Copyright (c) Yorik van Havre (yorik@uncreated.net) 2015 *
4
* This file is part of the FreeCAD CAx development system. *
6
* This library is free software; you can redistribute it and/or *
7
* modify it under the terms of the GNU Library General Public *
8
* License as published by the Free Software Foundation; either *
9
* version 2 of the License, or (at your option) any later version. *
11
* This library is distributed in the hope that it will be useful, *
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14
* GNU Library General Public License for more details. *
16
* You should have received a copy of the GNU Library General Public *
17
* License along with this library; see the file COPYING.LIB. If not, *
18
* write to the Free Software Foundation, Inc., 59 Temple Place, *
19
* Suite 330, Boston, MA 02111-1307, USA *
21
***************************************************************************/
23
#include "PreCompiled.h"
29
#include <App/PropertyUnits.h>
30
#include <Base/Exception.h>
31
#include <Mod/Spreadsheet/App/Cell.h>
32
#include <Mod/Spreadsheet/App/Sheet.h>
34
#include "FeatureViewSpreadsheet.h"
37
using namespace Drawing;
39
//===========================================================================
40
// FeatureViewSpreadsheet
41
//===========================================================================
43
PROPERTY_SOURCE(Drawing::FeatureViewSpreadsheet, Drawing::FeatureView)
46
FeatureViewSpreadsheet::FeatureViewSpreadsheet(void)
48
static const char* vgroup = "Drawing view";
50
ADD_PROPERTY_TYPE(CellStart,
54
"The top left cell of the range to display");
55
ADD_PROPERTY_TYPE(CellEnd,
59
"The bottom right cell of the range to display");
60
ADD_PROPERTY_TYPE(Font, ("Sans"), vgroup, App::Prop_None, "The name of the font to use");
61
ADD_PROPERTY_TYPE(Color,
65
"The default color of the text and lines");
66
ADD_PROPERTY_TYPE(Source, (nullptr), vgroup, App::Prop_None, "Spreadsheet to view");
67
ADD_PROPERTY_TYPE(LineWidth, (0.35), vgroup, App::Prop_None, "The thickness of the cell lines");
68
ADD_PROPERTY_TYPE(FontSize, (12.0), vgroup, App::Prop_None, "The size of the text");
72
FeatureViewSpreadsheet::~FeatureViewSpreadsheet()
75
App::DocumentObjectExecReturn* FeatureViewSpreadsheet::execute(void)
78
App::DocumentObject* link = Source.getValue();
79
std::string scellstart = CellStart.getValue();
80
std::string scellend = CellEnd.getValue();
82
return new App::DocumentObjectExecReturn("No spreadsheet linked");
84
if (!link->isDerivedFrom<Spreadsheet::Sheet>()) {
85
return new App::DocumentObjectExecReturn("The linked object is not a spreadsheet");
87
if ((scellstart.empty()) || (scellend.empty())) {
88
return new App::DocumentObjectExecReturn("Empty cell value");
91
// build a list of available columns: A, B, C, ... AA, AB, ... ZY, ZZ.
92
std::string alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
93
std::vector<std::string> availcolumns;
94
for (int i = 0; i < 26; ++i) {
97
availcolumns.push_back(s.str());
99
for (int i = 0; i < 26; ++i) {
100
for (int j = 0; i < 26; ++i) {
102
s << alphabet[i] << alphabet[j];
103
availcolumns.push_back(s.str());
107
// build rows range and columns range
108
std::vector<std::string> columns;
109
std::vector<int> rows;
111
for (unsigned int i = 0; i < scellstart.length(); ++i) {
112
if (isdigit(scellstart[i])) {
113
columns.push_back(scellstart.substr(0, i));
114
rows.push_back(std::atoi(scellstart.substr(i, scellstart.length() - 1).c_str()));
117
for (unsigned int i = 0; i < scellend.length(); ++i) {
118
if (isdigit(scellend[i])) {
119
std::string startcol = columns.back();
120
std::string endcol = scellend.substr(0, i);
122
for (std::vector<std::string>::const_iterator j = availcolumns.begin();
123
j != availcolumns.end();
125
if ((*j) == startcol) {
126
if ((*j) != endcol) {
132
if ((*j) == endcol) {
133
columns.push_back((*j));
137
columns.push_back((*j));
142
int endrow = std::atoi(scellend.substr(i, scellend.length() - 1).c_str());
143
for (int j = rows.back() + 1; j <= endrow; ++j) {
149
catch (std::exception&) {
150
return new App::DocumentObjectExecReturn("Invalid cell range");
153
// create the containing group
154
std::string ViewName = Label.getValue();
155
std::stringstream result, hr, hg, hb;
156
const App::Color& c = Color.getValue();
157
hr << std::hex << std::setfill('0') << std::setw(2) << (int)(255.0 * c.r);
158
hg << std::hex << std::setfill('0') << std::setw(2) << (int)(255.0 * c.g);
159
hb << std::hex << std::setfill('0') << std::setw(2) << (int)(255.0 * c.b);
160
result << "<g id=\"" << ViewName << "\" transform=\"translate(" << X.getValue() << ","
161
<< Y.getValue() << ")"
162
<< " rotate(" << Rotation.getValue() << ")"
163
<< " scale(" << Scale.getValue() << ")\">" << std::endl;
166
float rowoffset = 0.0;
167
float coloffset = 0.0;
168
float cellheight = 100;
169
float cellwidth = 100;
170
std::string celltext;
171
Spreadsheet::Sheet* sheet = static_cast<Spreadsheet::Sheet*>(link);
172
std::vector<std::string> skiplist;
173
for (std::vector<std::string>::const_iterator col = columns.begin(); col != columns.end();
175
// create a group for each column
176
result << " <g id=\"" << ViewName << "_col" << (*col) << "\">" << std::endl;
177
for (std::vector<int>::const_iterator row = rows.begin(); row != rows.end(); ++row) {
179
std::stringstream srow;
181
App::CellAddress address((*col) + srow.str());
182
cellwidth = sheet->getColumnWidth(address.col());
183
cellheight = sheet->getRowHeight(address.row());
186
App::Property* prop = sheet->getPropertyByName(address.toString().c_str());
187
std::stringstream field;
189
if (prop->isDerivedFrom((App::PropertyQuantity::getClassTypeId()))) {
190
field << static_cast<App::PropertyQuantity*>(prop)->getValue();
192
else if (prop->isDerivedFrom((App::PropertyFloat::getClassTypeId()))) {
193
field << static_cast<App::PropertyFloat*>(prop)->getValue();
195
else if (prop->isDerivedFrom((App::PropertyString::getClassTypeId()))) {
196
field << static_cast<App::PropertyString*>(prop)->getValue();
201
celltext = field.str();
203
// get colors, style, alignment and span
205
std::string bcolor = "none";
206
std::string fcolor = "#" + hr.str() + hg.str() + hb.str();
207
std::string textstyle = "";
208
Spreadsheet::Cell* cell = sheet->getCell(address);
211
std::set<std::string> st;
212
int colspan, rowspan;
213
if (cell->getBackground(b)) {
214
std::stringstream br, bg, bb;
215
br << std::hex << std::setfill('0') << std::setw(2) << (int)(255.0 * b.r);
216
bg << std::hex << std::setfill('0') << std::setw(2) << (int)(255.0 * b.g);
217
bb << std::hex << std::setfill('0') << std::setw(2) << (int)(255.0 * b.b);
218
bcolor = "#" + br.str() + bg.str() + bb.str();
220
if (cell->getForeground(f)) {
221
std::stringstream fr, fg, fb;
222
fr << std::hex << std::setfill('0') << std::setw(2) << (int)(255.0 * f.r);
223
fg << std::hex << std::setfill('0') << std::setw(2) << (int)(255.0 * f.g);
224
fb << std::hex << std::setfill('0') << std::setw(2) << (int)(255.0 * f.b);
225
fcolor = "#" + fr.str() + fg.str() + fb.str();
227
if (cell->getStyle(st)) {
228
for (std::set<std::string>::const_iterator i = st.begin(); i != st.end(); ++i) {
229
if ((*i) == "bold") {
230
textstyle = textstyle + "font-weight: bold; ";
232
else if ((*i) == "italic") {
233
textstyle = textstyle + "font-style: italic; ";
235
else if ((*i) == "underline") {
236
textstyle = textstyle + "text-decoration: underline; ";
240
if (cell->getSpans(rowspan, colspan)) {
241
for (int i = 0; i < colspan; ++i) {
242
for (int j = 0; j < rowspan; ++j) {
243
App::CellAddress nextcell(address.row() + j, address.col() + i);
245
cellwidth = cellwidth + sheet->getColumnWidth(nextcell.col());
248
cellheight = cellheight + sheet->getRowHeight(nextcell.row());
250
if ((i > 0) || (j > 0)) {
251
skiplist.push_back(nextcell.toString());
256
cell->getAlignment(alignment);
258
// skip cell if found in skiplist
259
if (std::find(skiplist.begin(), skiplist.end(), address.toString()) == skiplist.end()) {
260
result << " <rect x=\"" << coloffset << "\" y=\"" << rowoffset << "\" width=\""
261
<< cellwidth << "\" height=\"" << cellheight << "\" style=\"fill:" << bcolor
262
<< ";stroke-width:" << LineWidth.getValue() / Scale.getValue() << ";stroke:#"
263
<< hr.str() << hg.str() << hb.str() << ";\" />" << std::endl;
264
if (alignment & Spreadsheet::Cell::ALIGNMENT_LEFT) {
265
result << " <text style=\"" << textstyle << "\" x=\""
266
<< coloffset + FontSize.getValue() / 2 << "\" y=\""
267
<< rowoffset + 0.75 * cellheight << "\" font-family=\"";
269
if (alignment & Spreadsheet::Cell::ALIGNMENT_HCENTER) {
270
result << " <text text-anchor=\"middle\" style=\"" << textstyle << "\" x=\""
271
<< coloffset + cellwidth / 2 << "\" y=\""
272
<< rowoffset + 0.75 * cellheight << "\" font-family=\"";
274
if (alignment & Spreadsheet::Cell::ALIGNMENT_RIGHT) {
275
result << " <text text-anchor=\"end\" style=\"" << textstyle << "\" x=\""
276
<< coloffset + (cellwidth - FontSize.getValue() / 2) << "\" y=\""
277
<< rowoffset + 0.75 * cellheight << "\" font-family=\"";
279
result << Font.getValue() << "\""
280
<< " font-size=\"" << FontSize.getValue() << "\""
281
<< " fill=\"" << fcolor << "\">" << celltext << "</text>" << std::endl;
283
rowoffset = rowoffset + cellheight;
285
result << " </g>" << std::endl;
287
coloffset = coloffset + cellwidth;
290
// close the containing group
291
result << "</g>" << std::endl;
293
// Apply the resulting fragment
294
ViewResult.setValue(result.str().c_str());
296
return App::DocumentObject::StdReturn;