1 /*******************************************************************************
2  * Copyright (c) 2013-2021, Andrés Martinelli <andmarti@gmail.com>             *
3  * All rights reserved.                                                        *
4  *                                                                             *
5  * This file is a part of SC-IM                                                *
6  *                                                                             *
7  * SC-IM is a spreadsheet program that is based on SC. The original authors    *
8  * of SC are James Gosling and Mark Weiser, and mods were later added by       *
9  * Chuck Martin.                                                               *
10  *                                                                             *
11  * Redistribution and use in source and binary forms, with or without          *
12  * modification, are permitted provided that the following conditions are met: *
13  * 1. Redistributions of source code must retain the above copyright           *
14  *    notice, this list of conditions and the following disclaimer.            *
15  * 2. Redistributions in binary form must reproduce the above copyright        *
16  *    notice, this list of conditions and the following disclaimer in the      *
17  *    documentation and/or other materials provided with the distribution.     *
18  * 3. All advertising materials mentioning features or use of this software    *
19  *    must display the following acknowledgement:                              *
20  *    This product includes software developed by Andrés Martinelli            *
21  *    <andmarti@gmail.com>.                                                    *
22  * 4. Neither the name of the Andrés Martinelli nor the                        *
23  *   names of other contributors may be used to endorse or promote products    *
24  *   derived from this software without specific prior written permission.     *
25  *                                                                             *
26  * THIS SOFTWARE IS PROVIDED BY ANDRES MARTINELLI ''AS IS'' AND ANY            *
27  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED   *
28  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE      *
29  * DISCLAIMED. IN NO EVENT SHALL ANDRES MARTINELLI BE LIABLE FOR ANY           *
30  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES  *
31  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;*
32  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND *
33  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT  *
34  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE       *
35  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.           *
36  *******************************************************************************/
37 
38 /**
39  * \file shift.c
40  * \author Andrés Martinelli <andmarti@gmail.com>
41  * \date 2017-07-18
42  * \brief TODO Write a tbrief file description.
43  */
44 
45 #include <stdio.h>
46 #include <stdlib.h>
47 #include "shift.h"
48 #include "sc.h"
49 #include "vmtbl.h"   // for growtbl
50 #include "cmds.h"
51 #include "dep_graph.h"
52 #include "undo.h"
53 #include "marks.h"
54 #include "yank.h"
55 #include "conf.h"
56 #include "tui.h"
57 
58 extern graphADT graph;
59 extern int cmd_multiplier;
60 
61 /**
62  * @brief Shift function - handles undo
63  *
64  * Shift functin - handles unto. Should also be called form gram.y.
65  *
66  * \param[in] r
67  * \param[in] c
68  * \param[in] rf
69  * \param[in] cf
70  * \param[in] type
71  *
72  * \return none
73  */
74 
shift(int r,int c,int rf,int cf,wchar_t type)75 void shift(int r, int c, int rf, int cf, wchar_t type) {
76     if ( any_locked_cells(r, c, rf, cf) && (type == L'h' || type == L'k') ) {
77         sc_error("Locked cells encountered. Nothing changed");
78         return;
79     }
80 #ifdef UNDO
81     create_undo_action();
82 #endif
83     int ic = cmd_multiplier + 1;
84 
85     switch (type) {
86 
87         case L'j':
88             fix_marks(  (rf - r + 1) * cmd_multiplier, 0, r, maxrow, c, cf);
89 #ifdef UNDO
90             save_undo_range_shift(cmd_multiplier, 0, r, c, rf + (rf-r+1) * (cmd_multiplier - 1), cf);
91 #endif
92             while (ic--) shift_range(ic, 0, r, c, rf, cf);
93             break;
94 
95         case L'k':
96             fix_marks( -(rf - r + 1) * cmd_multiplier, 0, r, maxrow, c, cf);
97             yank_area(r, c, rf + (rf-r+1) * (cmd_multiplier - 1), cf, 'a', cmd_multiplier); // keep ents in yanklist for sk
98 #ifdef UNDO
99             ents_that_depends_on_range(r, c, rf + (rf-r+1) * (cmd_multiplier - 1), cf);
100             copy_to_undostruct(r, c, rf + (rf-r+1) * (cmd_multiplier - 1), cf, UNDO_DEL, HANDLE_DEPS, NULL);
101             save_undo_range_shift(-cmd_multiplier, 0, r, c, rf + (rf-r+1) * (cmd_multiplier - 1), cf);
102 #endif
103             while (ic--) shift_range(-ic, 0, r, c, rf, cf);
104             if (get_conf_int("autocalc") && ! loading) EvalAll();
105 #ifdef UNDO
106             copy_to_undostruct(0, 0, -1, -1, UNDO_ADD, HANDLE_DEPS, NULL);
107 #endif
108             break;
109 
110         case L'h':
111             fix_marks(0, -(cf - c + 1) * cmd_multiplier, r, rf, c, maxcol);
112             yank_area(r, c, rf, cf + (cf-c+1) * (cmd_multiplier - 1), 'a', cmd_multiplier); // keep ents in yanklist for sk
113 #ifdef UNDO
114             // here we save in undostruct, all the ents that depends on the deleted one (before change)
115             ents_that_depends_on_range(r, c, rf, cf + (cf-c+1) * (cmd_multiplier - 1));
116             copy_to_undostruct(r, c, rf, cf + (cf-c+1) * (cmd_multiplier - 1), UNDO_DEL, HANDLE_DEPS, NULL);
117             save_undo_range_shift(0, -cmd_multiplier, r, c, rf, cf + (cf-c+1) * (cmd_multiplier - 1));
118 #endif
119             while (ic--) shift_range(0, -ic, r, c, rf, cf);
120 
121             if (get_conf_int("autocalc") && ! loading) EvalAll();
122             //update(TRUE); // this is used just to make debugging easier
123 #ifdef UNDO
124             copy_to_undostruct(0, 0, -1, -1, UNDO_ADD, HANDLE_DEPS, NULL);
125 #endif
126             break;
127 
128         case L'l':
129             fix_marks(0,  (cf - c + 1) * cmd_multiplier, r, rf, c, maxcol);
130 #ifdef UNDO
131             save_undo_range_shift(0, cmd_multiplier, r, c, rf, cf + (cf-c+1) * (cmd_multiplier - 1));
132 #endif
133             while (ic--) shift_range(0, ic, r, c, rf, cf);
134             break;
135     }
136 #ifdef UNDO
137     end_undo_action();
138     extern struct ent_ptr * deps;
139     if (deps != NULL) free(deps);
140     deps = NULL;
141 #endif
142     /* just for testing
143     sync_refs();
144     rebuild_graph();
145     sync_refs();
146     rebuild_graph(); */
147     cmd_multiplier = 0;
148     return;
149 }
150 
151 /**
152  * \brief Shift a range to 'ENTS'
153  *
154  * \param[in] delta_rows
155  * \param[in] delta_cols
156  * \param[in] tlrow
157  * \param[in] tlcol
158  * \param[in] brrow
159  * \param[in] brcol
160  *
161  * \return none
162  */
163 
shift_range(int delta_rows,int delta_cols,int tlrow,int tlcol,int brrow,int brcol)164 void shift_range(int delta_rows, int delta_cols, int tlrow, int tlcol, int brrow, int brcol) {
165     currow = tlrow;
166     curcol = tlcol;
167 
168     if (delta_rows > 0)      shift_cells_down (brrow - tlrow + 1, brcol - tlcol + 1);
169     else if (delta_rows < 0) shift_cells_up   (brrow - tlrow + 1, brcol - tlcol + 1);
170 
171     if (delta_cols > 0)      shift_cells_right(brrow - tlrow + 1, brcol - tlcol + 1);
172     else if (delta_cols < 0) shift_cells_left (brrow - tlrow + 1, brcol - tlcol + 1);
173 
174     return;
175 }
176 
177 /**
178  * \brief Shift cells down
179  *
180  * \param[in] deltarows
181  * \param[in] deltacols
182  *
183  * \return none
184  */
185 
shift_cells_down(int deltarows,int deltacols)186 void shift_cells_down(int deltarows, int deltacols) {
187     int r, c;
188     struct ent ** pp;
189     if (currow > maxrow) maxrow = currow;
190     maxrow += deltarows;
191     if ((maxrow >= maxrows) && !growtbl(GROWROW, maxrow, 0))
192         return;
193 
194     for (r = maxrow; r > currow + deltarows - 1; r--) {
195         for (c = curcol; c < curcol + deltacols; c++) {
196             pp = ATBL(tbl, r, c);
197             pp[0] = *ATBL(tbl, r-deltarows, c);
198             if ( pp[0] ) pp[0]->row += deltarows;
199         }
200     }
201     // blank new ents
202     for (c = curcol; c < curcol + deltacols; c++)
203         for (r = currow; r < currow + deltarows; r++) {
204             pp = ATBL(tbl, r, c);
205             *pp = (struct ent *) 0;
206         }
207     return;
208 }
209 
210 /**
211  * \brief Shift cells right
212  *
213  * \param[in] deltaros
214  * \param[in] deltacols
215  *
216  * \return none
217  */
218 
shift_cells_right(int deltarows,int deltacols)219 void shift_cells_right(int deltarows, int deltacols) {
220     int r, c;
221     struct ent ** pp;
222 
223     if (curcol + deltacols > maxcol)
224         maxcol = curcol + deltacols;
225     maxcol += deltacols;
226 
227     if ((maxcol >= maxcols) && !growtbl(GROWCOL, 0, maxcol))
228         return;
229 
230     int lim = maxcol - curcol - deltacols;
231     for (r=currow; r < currow + deltarows; r++) {
232         pp = ATBL(tbl, r, maxcol);
233         for (c = lim; c-- >= 0; pp--)
234             if ((pp[0] = pp[-deltacols])) pp[0]->col += deltacols;
235 
236         pp = ATBL(tbl, r, curcol);
237         for (c = curcol; c < curcol + deltacols; c++, pp++)
238             *pp = (struct ent *) 0;
239     }
240     return;
241 }
242 
243 /**
244  * \brief Shift cells up
245  *
246  * \param[in] deltarows
247  * \param[in] deltacols
248  *
249  * \return none
250  */
251 
shift_cells_up(int deltarows,int deltacols)252 void shift_cells_up(int deltarows, int deltacols) {
253     int r, c;
254     struct ent ** pp;
255 
256     for (r = currow; r <= maxrow; r++) {
257         for (c = curcol; c < curcol + deltacols; c++) {
258 
259             if (r < currow + deltarows) {
260                 pp = ATBL(tbl, r, c);
261 
262                 /* delete vertex in graph
263                    unless vertex is referenced by other. Shall comment this? See NOTE1 above */
264                 vertexT * v = getVertex(graph, *pp, 0);
265                 if (v != NULL && v->back_edges == NULL ) destroy_vertex(*pp);
266 
267                 if (*pp) {
268                    mark_ent_as_deleted(*pp, TRUE); //important: this mark the ents as deleted
269                    //clearent(*pp);
270                    //free(*pp);
271                    *pp = NULL;
272                 }
273             }
274             if (r <= maxrow - deltarows) {
275                 pp = ATBL(tbl, r, c);
276                 pp[0] = *ATBL(tbl, r + deltarows, c);
277                 if ( pp[0] ) pp[0]->row -= deltarows;
278             }
279             //blank bottom ents
280             if (r > maxrow - deltarows) {
281                 pp = ATBL(tbl, r, c);
282                 *pp = (struct ent *) 0;
283             }
284         }
285     }
286     return;
287 }
288 
289 /**
290  * \brief Shift cells left
291  *
292  * \param[in] deltarows
293  * \param[in] deltacols
294  *
295  * \return none
296  */
297 
shift_cells_left(int deltarows,int deltacols)298 void shift_cells_left(int deltarows, int deltacols) {
299     int r, c;
300     struct ent ** pp;
301 
302     for (c = curcol; c <= maxcol; c++) {
303         for (r = currow; r < currow + deltarows; r++) {
304 
305             if (c < curcol + deltacols) {
306                 pp = ATBL(tbl, r, c);
307 
308                 /* delete vertex in graph
309                    unless vertex is referenced by other */
310                 vertexT * v = getVertex(graph, *pp, 0);
311                 if (v != NULL && v->back_edges == NULL ) destroy_vertex(*pp);
312 
313                 if (*pp) {
314                    mark_ent_as_deleted(*pp, TRUE); //important: this mark the ents as deleted
315                    //clearent(*pp);
316                    //free(*pp);
317                    *pp = NULL;
318                 }
319             }
320             if (c <= maxcol - deltacols) {
321                 pp = ATBL(tbl, r, c);
322                 pp[0] = *ATBL(tbl, r, c + deltacols);
323                 if ( pp[0] ) pp[0]->col -= deltacols;
324             }
325             //blank bottom ents
326             if (c > maxcol - deltacols) {
327                 pp = ATBL(tbl, r, c);
328                 *pp = (struct ent *) 0;
329             }
330         }
331     }
332     return;
333 }
334