1 /* This file is part of the KDE project
2    Copyright (C) 2005 Tomas Mecir <mecirt@gmail.com>
3    Copyright (C) 2000 Torben Weis <weis@kde.org>
4 
5    This library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Library General Public
7    License as published by the Free Software Foundation; either
8    version 2 of the License, or (at your option) any later version.
9 
10    This library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Library General Public License for more details.
14 
15    You should have received a copy of the GNU Library General Public License
16    along with this library; see the file COPYING.LIB.  If not, write to
17    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18    Boston, MA 02110-1301, USA.
19 */
20 
21 // Local
22 #include "Cluster.h"
23 
24 #include <stdlib.h>
25 
26 #include "SheetsDebug.h"
27 #include "Cell.h"
28 #include "RowColumnFormat.h"
29 
30 using namespace Calligra::Sheets;
31 
32 /****************************************************
33  *
34  * ColumnCluster
35  *
36  ****************************************************/
37 
ColumnCluster()38 ColumnCluster::ColumnCluster()
39         : m_first(0), m_autoDelete(false)
40 {
41     m_cluster = (ColumnFormat***)malloc(CALLIGRA_SHEETS_CLUSTER_LEVEL1 * sizeof(ColumnFormat**));
42 
43     for (int x = 0; x < CALLIGRA_SHEETS_CLUSTER_LEVEL1; ++x)
44         m_cluster[ x ] = 0;
45 }
46 
~ColumnCluster()47 ColumnCluster::~ColumnCluster()
48 {
49     for (int x = 0; x < CALLIGRA_SHEETS_CLUSTER_LEVEL1; ++x) {
50         ColumnFormat** cl = m_cluster[ x ];
51         if (cl) {
52             free(cl);
53             m_cluster[ x ] = 0;
54         }
55     }
56 
57     if (m_autoDelete) {
58         ColumnFormat* cell = m_first;
59         while (cell) {
60             ColumnFormat* n = cell->next();
61             delete cell;
62             cell = n;
63         }
64     }
65 
66 
67     free(m_cluster);
68 }
69 
lookup(int col)70 ColumnFormat* ColumnCluster::lookup(int col)
71 {
72     if (col >= CALLIGRA_SHEETS_CLUSTER_MAX || col < 0) {
73         debugSheets << "ColumnCluster::lookup: invalid column value (col:"
74         << col << ")" << endl;
75         return 0;
76     }
77 
78     int cx = col / CALLIGRA_SHEETS_CLUSTER_LEVEL2;
79     int dx = col % CALLIGRA_SHEETS_CLUSTER_LEVEL2;
80 
81     ColumnFormat** cl = m_cluster[ cx ];
82     if (!cl)
83         return 0;
84 
85     return cl[ dx ];
86 }
87 
lookup(int col) const88 const ColumnFormat* ColumnCluster::lookup(int col) const
89 {
90     if (col >= CALLIGRA_SHEETS_CLUSTER_MAX || col < 0) {
91         debugSheets << "ColumnCluster::lookup: invalid column value (col:"
92         << col << ")" << endl;
93         return 0;
94     }
95 
96     int cx = col / CALLIGRA_SHEETS_CLUSTER_LEVEL2;
97     int dx = col % CALLIGRA_SHEETS_CLUSTER_LEVEL2;
98 
99     ColumnFormat** cl = m_cluster[ cx ];
100     if (!cl)
101         return 0;
102 
103     return cl[ dx ];
104 }
105 
clear()106 void ColumnCluster::clear()
107 {
108     for (int x = 0; x < CALLIGRA_SHEETS_CLUSTER_LEVEL1; ++x) {
109         ColumnFormat** cl = m_cluster[ x ];
110         if (cl) {
111             free(cl);
112             m_cluster[ x ] = 0;
113         }
114     }
115 
116     if (m_autoDelete) {
117         ColumnFormat* cell = m_first;
118         while (cell) {
119             ColumnFormat* n = cell->next();
120             delete cell;
121             cell = n;
122         }
123     }
124 
125     m_first = 0;
126 }
127 
insertElement(ColumnFormat * lay,int col)128 void ColumnCluster::insertElement(ColumnFormat* lay, int col)
129 {
130     if (col >= CALLIGRA_SHEETS_CLUSTER_MAX || col < 0) {
131         debugSheets << "ColumnCluster::insertElement: invalid column value (col:"
132         << col << ")" << endl;
133         return;
134     }
135 
136     int cx = col / CALLIGRA_SHEETS_CLUSTER_LEVEL2;
137     int dx = col % CALLIGRA_SHEETS_CLUSTER_LEVEL2;
138 
139     ColumnFormat** cl = m_cluster[ cx ];
140     if (!cl) {
141         cl = (ColumnFormat**)malloc(CALLIGRA_SHEETS_CLUSTER_LEVEL2 * sizeof(ColumnFormat*));
142         m_cluster[ cx ] = cl;
143 
144         for (int a = 0; a < CALLIGRA_SHEETS_CLUSTER_LEVEL2; ++a)
145             cl[ a ] = 0;
146     }
147 
148     if (cl[ dx ])
149         removeElement(col);
150 
151     cl[ dx ] = lay;
152 
153     if (m_first) {
154         lay->setNext(m_first);
155         m_first->setPrevious(lay);
156     }
157     m_first = lay;
158 }
159 
removeElement(int col)160 void ColumnCluster::removeElement(int col)
161 {
162     if (col >= CALLIGRA_SHEETS_CLUSTER_MAX || col < 0) {
163         debugSheets << "ColumnCluster::removeElement: invalid column value (col:"
164         << col << ")" << endl;
165         return;
166     }
167 
168     int cx = col / CALLIGRA_SHEETS_CLUSTER_LEVEL2;
169     int dx = col % CALLIGRA_SHEETS_CLUSTER_LEVEL2;
170 
171     ColumnFormat** cl = m_cluster[ cx ];
172     if (!cl)
173         return;
174 
175     ColumnFormat* c = cl[ dx ];
176     if (!c)
177         return;
178 
179     cl[ dx ] = 0;
180 
181     if (m_autoDelete) {
182         if (m_first == c)
183             m_first = c->next();
184         delete c;
185     } else {
186         if (m_first == c)
187             m_first = c->next();
188         if (c->previous())
189             c->previous()->setNext(c->next());
190         if (c->next())
191             c->next()->setPrevious(c->previous());
192         c->setNext(0);
193         c->setPrevious(0);
194     }
195 }
196 
insertColumn(int col)197 bool ColumnCluster::insertColumn(int col)
198 {
199     if (col >= CALLIGRA_SHEETS_CLUSTER_MAX || col < 0) {
200         debugSheets << "ColumnCluster::insertColumn: invalid column value (col:"
201         << col << ")" << endl;
202         return false;
203     }
204 
205     int cx = col / CALLIGRA_SHEETS_CLUSTER_LEVEL2;
206     int dx = col % CALLIGRA_SHEETS_CLUSTER_LEVEL2;
207 
208     // Is there a column layout at the right most position ?
209     // In this case the shift is impossible.
210     ColumnFormat** cl = m_cluster[ CALLIGRA_SHEETS_CLUSTER_LEVEL1 - 1 ];
211     if (cl && cl[ CALLIGRA_SHEETS_CLUSTER_LEVEL2 - 1 ])
212         return false;
213 
214     bool a = autoDelete();
215     setAutoDelete(false);
216 
217     for (int i = CALLIGRA_SHEETS_CLUSTER_LEVEL1 - 1; i >= cx ; --i) {
218         ColumnFormat** cl = m_cluster[ i ];
219         if (cl) {
220             int left = 0;
221             if (i == cx)
222                 left = dx;
223             int right = CALLIGRA_SHEETS_CLUSTER_LEVEL2 - 1;
224             if (i == CALLIGRA_SHEETS_CLUSTER_LEVEL1 - 1)
225                 right = CALLIGRA_SHEETS_CLUSTER_LEVEL2 - 2;
226             for (int k = right; k >= left; --k) {
227                 ColumnFormat* c = cl[ k ];
228                 if (c) {
229                     removeElement(c->column());
230                     c->setColumn(c->column() + 1);
231                     insertElement(c, c->column());
232                 }
233             }
234         }
235     }
236 
237     setAutoDelete(a);
238 
239     return true;
240 }
241 
removeColumn(int column)242 bool ColumnCluster::removeColumn(int column)
243 {
244     if (column >= CALLIGRA_SHEETS_CLUSTER_MAX || column < 0) {
245         debugSheets << "ColumnCluster::removeColumn: invalid column value (col:"
246         << column << ")" << endl;
247         return false;
248     }
249 
250     int cx = column / CALLIGRA_SHEETS_CLUSTER_LEVEL2;
251     int dx = column % CALLIGRA_SHEETS_CLUSTER_LEVEL2;
252 
253     removeElement(column);
254 
255     bool a = autoDelete();
256     setAutoDelete(false);
257 
258     for (int i = cx; i < CALLIGRA_SHEETS_CLUSTER_LEVEL1; ++i) {
259         ColumnFormat** cl = m_cluster[ i ];
260         if (cl) {
261             int left = 0;
262             if (i == cx)
263                 left = dx + 1;
264             int right = CALLIGRA_SHEETS_CLUSTER_LEVEL2 - 1;
265             for (int k = left; k <= right; ++k) {
266                 ColumnFormat* c = cl[ k ];
267                 if (c) {
268                     removeElement(c->column());
269                     c->setColumn(c->column() - 1);
270                     insertElement(c, c->column());
271                 }
272             }
273         }
274     }
275 
276     setAutoDelete(a);
277 
278     return true;
279 }
280 
setAutoDelete(bool a)281 void ColumnCluster::setAutoDelete(bool a)
282 {
283     m_autoDelete = a;
284 }
285 
autoDelete() const286 bool ColumnCluster::autoDelete() const
287 {
288     return m_autoDelete;
289 }
290 
next(int col) const291 ColumnFormat* ColumnCluster::next(int col) const
292 {
293     if (col >= CALLIGRA_SHEETS_CLUSTER_MAX || col < 0) {
294         debugSheets << "ColumnCluster::next: invalid column value (col:"
295         << col << ")" << endl;
296         return 0;
297     }
298 
299     int cx = (col + 1) / CALLIGRA_SHEETS_CLUSTER_LEVEL2;
300     int dx = (col + 1) % CALLIGRA_SHEETS_CLUSTER_LEVEL2;
301 
302     while (cx < CALLIGRA_SHEETS_CLUSTER_LEVEL1) {
303         if (m_cluster[ cx ]) {
304             while (dx < CALLIGRA_SHEETS_CLUSTER_LEVEL2) {
305 
306                 if (m_cluster[ cx ][  dx ]) {
307                     return m_cluster[ cx ][ dx ];
308                 }
309                 ++dx;
310             }
311         }
312         ++cx;
313         dx = 0;
314     }
315     return 0;
316 }
317 
operator =(const ColumnCluster & other)318 void ColumnCluster::operator=(const ColumnCluster & other)
319 {
320     m_first = 0;
321     m_autoDelete = other.m_autoDelete;
322     // TODO Stefan: Optimize!
323     m_cluster = (ColumnFormat***)malloc(CALLIGRA_SHEETS_CLUSTER_LEVEL1 * sizeof(ColumnFormat**));
324     for (int i = 0; i < CALLIGRA_SHEETS_CLUSTER_LEVEL1; ++i) {
325         if (other.m_cluster[i]) {
326             m_cluster[i] = (ColumnFormat**)malloc(CALLIGRA_SHEETS_CLUSTER_LEVEL2 * sizeof(ColumnFormat*));
327             for (int j = 0; j < CALLIGRA_SHEETS_CLUSTER_LEVEL2; ++j) {
328                 m_cluster[i][j] = 0;
329                 if (other.m_cluster[i][j]) {
330                     ColumnFormat* columnFormat = new ColumnFormat(*other.m_cluster[i][j]);
331                     columnFormat->setNext(0);
332                     columnFormat->setPrevious(0);
333                     insertElement(columnFormat, columnFormat->column());
334                 }
335             }
336         } else
337             m_cluster[i] = 0;
338     }
339 }
340 
341 
342