1 /* AbiWord
2 * Copyright (c) 2003 Martin Sevior <msevior@physics.unimelb.edu.au>
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17 * 02110-1301 USA.
18 */
19
20 #include "fv_Selection.h"
21 #include "fl_DocLayout.h"
22 #include "pd_Document.h"
23 #include "ut_units.h"
24 #include "fl_BlockLayout.h"
25 #include "fp_Line.h"
26 #include "fp_Run.h"
27 #include "pf_Frag.h"
28 #include "pf_Frag_Strux.h"
29 #include "fl_TableLayout.h"
30 #include "pd_Document.h"
31 #include "ie_exp.h"
32 #include "ie_exp_RTF.h"
33 #include "fl_TOCLayout.h"
34 #include "ie_imp.h"
35 #include "ie_imp_RTF.h"
36
37 #include "ut_bytebuf.h"
38 #include "fv_View.h"
39
FV_Selection(FV_View * pView)40 FV_Selection::FV_Selection (FV_View * pView)
41 : m_pView (pView),
42 m_iSelectionMode(FV_SelectionMode_NONE),
43 m_iPrevSelectionMode(FV_SelectionMode_NONE),
44 m_iSelectAnchor(0),
45 m_iSelectLeftAnchor(0),
46 m_iSelectRightAnchor(0),
47 m_pTableOfSelectedColumn(NULL),
48 m_pSelectedTOC(NULL),
49 m_bSelectAll(false)
50 {
51 UT_ASSERT (pView);
52 m_vecSelRanges.clear();
53 m_vecSelRTFBuffers.clear();
54 }
55
~FV_Selection()56 FV_Selection::~FV_Selection()
57 {
58 m_pTableOfSelectedColumn = NULL;
59 m_pSelectedTOC = NULL;
60 UT_VECTOR_PURGEALL(PD_DocumentRange *,m_vecSelRanges);
61 UT_VECTOR_PURGEALL(UT_ByteBuf *,m_vecSelRTFBuffers);
62 UT_VECTOR_PURGEALL(FV_SelectionCellProps *,m_vecSelCellProps);
63 }
64
checkSelectAll(void)65 void FV_Selection::checkSelectAll(void)
66 {
67 fl_SectionLayout * pSL = m_pView->m_pLayout->getLastSection();
68 if(pSL == NULL)
69 return;
70 if(m_pView->m_pDoc->isPieceTableChanging())
71 {
72 return;
73 }
74 if(m_pView->m_pLayout->isLayoutFilling())
75 {
76 return;
77 }
78 PT_DocPosition posLow = m_iSelectAnchor;
79 PT_DocPosition posHigh = m_pView->getPoint();
80 if(posHigh < posLow)
81 {
82 posHigh = m_iSelectAnchor;
83 posLow = m_pView->getPoint();
84 }
85 PT_DocPosition posBeg,posEnd=0;
86 m_pView->getEditableBounds(false,posBeg);
87 m_pView->getEditableBounds(true,posEnd);
88 xxx_UT_DEBUGMSG(("posLow %d posBeg %d posHigh %d posEnd %d\n",posLow,posBeg,posHigh,posEnd));
89 bool bSelAll = ((posBeg >= posLow) && (posEnd == posHigh));
90 setSelectAll(bSelAll);
91 }
92
setSelectAll(bool bSelectAll)93 void FV_Selection::setSelectAll(bool bSelectAll)
94 {
95 xxx_UT_DEBUGMSG(("Select All = %d \n",bSelectAll));
96 m_bSelectAll = bSelectAll;
97 }
setMode(FV_SelectionMode iSelMode)98 void FV_Selection::setMode(FV_SelectionMode iSelMode)
99 {
100 if( (m_iSelectionMode != FV_SelectionMode_NONE) || (iSelMode != FV_SelectionMode_NONE))
101 {
102 m_iPrevSelectionMode = m_iSelectionMode;
103 }
104 if((m_iSelectionMode == FV_SelectionMode_TOC) && (m_iSelectionMode != iSelMode))
105 {
106 if(m_pSelectedTOC)
107 {
108 m_pSelectedTOC->setSelected(false);
109 }
110 m_pSelectedTOC = NULL;
111 }
112 m_iSelectionMode = iSelMode;
113 if(m_iSelectionMode != FV_SelectionMode_NONE)
114 {
115 m_pTableOfSelectedColumn = NULL;
116 UT_VECTOR_PURGEALL(PD_DocumentRange *,m_vecSelRanges);
117 UT_VECTOR_PURGEALL(UT_ByteBuf *,m_vecSelRTFBuffers);
118 UT_VECTOR_PURGEALL(FV_SelectionCellProps *,m_vecSelCellProps);
119 m_vecSelRanges.clear();
120 m_vecSelRTFBuffers.clear();
121 m_vecSelCellProps.clear();
122 }
123 setSelectAll(false);
124 }
125
setTOCSelected(fl_TOCLayout * pTOCL)126 void FV_Selection::setTOCSelected(fl_TOCLayout * pTOCL)
127 {
128 UT_return_if_fail(pTOCL);
129 setMode(FV_SelectionMode_TOC);
130 m_pSelectedTOC = pTOCL;
131 m_iSelectAnchor = pTOCL->getPosition();
132 pTOCL->setSelected(true);
133 setSelectAll(false);
134 }
135
pasteRowOrCol(void)136 void FV_Selection::pasteRowOrCol(void)
137 {
138 pf_Frag_Strux* cellSDH, *tableSDH;
139 PT_DocPosition pos = m_pView->getPoint();
140 if(m_iPrevSelectionMode == FV_SelectionMode_TableColumn)
141 {
142 //
143 // GLOB stuff together so it undo's in one go.
144 //
145 getDoc()->beginUserAtomicGlob();
146 //
147 // Insert a column after the current column
148 //
149 m_pView->cmdInsertCol(m_pView->getPoint(),false);
150 //
151 // Now do all the encapsulating stuff for piecetable manipulations.
152 //
153 // Signal PieceTable Change
154 m_pView->_saveAndNotifyPieceTableChange();
155
156 // Turn off list updates
157
158 getDoc()->disableListUpdates();
159 if (!m_pView->isSelectionEmpty())
160 {
161 m_pView->_clearSelection();
162 }
163 getDoc()->setDontImmediatelyLayout(true);
164 pos = m_pView->getPoint();
165 PT_DocPosition posTable,posCell;
166 UT_sint32 iLeft,iRight,iTop,iBot;
167 posCell = 0;
168 m_pView->getCellParams(pos, &iLeft, &iRight,&iTop,&iBot);
169 bool bRes = getDoc()->getStruxOfTypeFromPosition(pos,PTX_SectionCell,&cellSDH);
170 bRes = getDoc()->getStruxOfTypeFromPosition(pos,PTX_SectionTable,&tableSDH);
171 UT_return_if_fail(bRes);
172 posTable = getDoc()->getStruxPosition(tableSDH) + 1;
173 UT_sint32 numRows = 0;
174 UT_sint32 numCols = 0;
175 UT_sint32 i = 0;
176 getDoc()-> getRowsColsFromTableSDH(tableSDH, m_pView->isShowRevisions(), m_pView->getRevisionLevel(),
177 &numRows, &numCols);
178
179 PD_DocumentRange DocRange(getDoc(),posCell,posCell);
180 for(i=0; i<getNumSelections();i++)
181 {
182 posCell = m_pView->findCellPosAt(posTable,i,iLeft)+2;
183 m_pView->setPoint(posCell);
184 PD_DocumentRange * pR = getNthSelection(i);
185 if(pR->m_pos1 == pR->m_pos2)
186 {
187 //
188 // Dont paste empty cells
189 //
190 continue;
191 }
192 UT_ByteBuf * pBuf = m_vecSelRTFBuffers.getNthItem(i);
193 const unsigned char * pData = pBuf->getPointer(0);
194 UT_uint32 iLen = pBuf->getLength();
195 DocRange.m_pos1 = posCell;
196 DocRange.m_pos2 = posCell;
197 IE_Imp_RTF * pImpRTF = new IE_Imp_RTF(getDoc());
198 pImpRTF->pasteFromBuffer(&DocRange,pData,iLen);
199 DELETEP(pImpRTF);
200 fl_SectionLayout * pSL = m_pView->getCurrentBlock()->getSectionLayout();
201 pSL->checkAndAdjustCellSize();
202 }
203 getDoc()->endUserAtomicGlob();
204 getDoc()->setDontImmediatelyLayout(false);
205 m_pView->_generalUpdate();
206
207
208 // restore updates and clean up dirty lists
209 getDoc()->enableListUpdates();
210 getDoc()->updateDirtyLists();
211
212 // Signal PieceTable Changes have finished
213 m_pView->_restorePieceTableState();
214 // Put the insertion point in a legal position
215 //
216 m_pView->notifyListeners(AV_CHG_MOTION);
217 m_pView->_fixInsertionPointCoords();
218 m_pView->_ensureInsertionPointOnScreen();
219
220 }
221 else
222 {
223 }
224 }
225
getTableLayout(void) const226 fl_TableLayout * FV_Selection::getTableLayout(void) const
227 {
228 return m_pTableOfSelectedColumn;
229 }
230
getDoc(void) const231 PD_Document * FV_Selection::getDoc(void) const
232 {
233 return m_pView->getDocument();
234 }
235
getLayout(void) const236 FL_DocLayout * FV_Selection::getLayout(void) const
237 {
238 return m_pView->getLayout();
239 }
240
getSelectionAnchor(void) const241 PT_DocPosition FV_Selection::getSelectionAnchor(void) const
242 {
243 if((m_iSelectionMode < FV_SelectionMode_Multiple) || (m_vecSelRanges.getItemCount() == 0))
244 {
245 return m_iSelectAnchor;
246 }
247 PD_DocumentRange * pDocRange = m_vecSelRanges.getNthItem(0);
248 return pDocRange->m_pos1;
249 }
250
setSelectionAnchor(PT_DocPosition pos)251 void FV_Selection::setSelectionAnchor(PT_DocPosition pos)
252 {
253 m_iSelectAnchor = pos;
254 fl_SectionLayout * pSL = m_pView->m_pLayout->getLastSection();
255 if(pSL == NULL)
256 return;
257 PT_DocPosition posLow = m_iSelectAnchor;
258 PT_DocPosition posHigh = m_pView->getPoint();
259 if(posHigh < posLow)
260 {
261 posHigh = m_iSelectAnchor;
262 posLow = m_pView->getPoint();
263 }
264 PT_DocPosition posBeg,posEnd=0;
265 m_pView->getEditableBounds(false,posBeg);
266 m_pView->getEditableBounds(true,posEnd);
267 xxx_UT_DEBUGMSG(("posLow %d posBeg %d posHigh %d posEnd %d\n",posLow,posBeg,posHigh,posEnd));
268 bool bSelAll = ((posBeg >= posLow) && (posEnd <= posHigh));
269 setSelectAll(bSelAll);
270 }
271
272
getSelectionLeftAnchor(void) const273 PT_DocPosition FV_Selection::getSelectionLeftAnchor(void) const
274 {
275 if((m_iSelectionMode < FV_SelectionMode_Multiple) || (m_vecSelRanges.getItemCount() == 0))
276 {
277 return m_iSelectLeftAnchor;
278 }
279 PD_DocumentRange * pDocRange = m_vecSelRanges.getNthItem(0);
280 return pDocRange->m_pos1;
281 }
282
setSelectionLeftAnchor(PT_DocPosition pos)283 void FV_Selection::setSelectionLeftAnchor(PT_DocPosition pos)
284 {
285 if(pos == 0)
286 return;
287 m_iSelectLeftAnchor = pos;
288 PT_DocPosition posBeg,posEnd=0;
289 m_pView->getEditableBounds(false,posBeg);
290 m_pView->getEditableBounds(true,posEnd);
291 bool bSelAll = ((posBeg >= m_iSelectLeftAnchor) && (posEnd <= m_iSelectRightAnchor));
292 xxx_UT_DEBUGMSG(("setleft posBeg %d left %d posEnd %d right %d\n",posBeg,m_iSelectLeftAnchor,posEnd,m_iSelectRightAnchor));
293 setSelectAll(bSelAll);
294 }
295
296
getSelectionRightAnchor(void) const297 PT_DocPosition FV_Selection::getSelectionRightAnchor(void) const
298 {
299 if((m_iSelectionMode < FV_SelectionMode_Multiple) || (m_vecSelRanges.getItemCount() == 0) )
300 {
301 return m_iSelectRightAnchor;
302 }
303 PD_DocumentRange * pDocRange = m_vecSelRanges.getNthItem(0);
304 return pDocRange->m_pos2;
305 }
306
setSelectionRightAnchor(PT_DocPosition pos)307 void FV_Selection::setSelectionRightAnchor(PT_DocPosition pos)
308 {
309 if(pos == 0)
310 return;
311 m_iSelectRightAnchor = pos;
312 PT_DocPosition posBeg,posEnd=0;
313 m_pView->getEditableBounds(false,posBeg);
314 m_pView->getEditableBounds(true,posEnd);
315 bool bSelAll = ((posBeg >= m_iSelectLeftAnchor) && (posEnd <= m_iSelectRightAnchor));
316 xxx_UT_DEBUGMSG(("setRight posBeg %d left %d posEnd %d right %d\n",posBeg,m_iSelectLeftAnchor,posEnd,m_iSelectRightAnchor));
317 setSelectAll(bSelAll);
318 }
319
isPosSelected(PT_DocPosition pos) const320 bool FV_Selection::isPosSelected(PT_DocPosition pos) const
321 {
322 if(m_iSelectionMode == FV_SelectionMode_NONE)
323 {
324 return false;
325 }
326 if(m_iSelectionMode < FV_SelectionMode_Multiple)
327 {
328 if(m_iSelectAnchor == m_pView->getPoint())
329 {
330 return false;
331 }
332 xxx_UT_DEBUGMSG(("m_iSelectAnchor %d \n",m_iSelectAnchor));
333 PT_DocPosition posLow = m_iSelectAnchor;
334 PT_DocPosition posHigh = m_pView->getPoint();
335 if(posHigh < posLow)
336 {
337 posHigh = m_iSelectAnchor;
338 posLow = m_pView->getPoint();
339 }
340 return ((pos >= posLow) && (pos <=posHigh));
341 }
342 UT_sint32 i =0;
343 for(i=0; i < m_vecSelRanges.getItemCount(); i++)
344 {
345 PD_DocumentRange * pDocRange = m_vecSelRanges.getNthItem(i);
346 xxx_UT_DEBUGMSG(("Looking at pos %d low %d high %d \n",pos, pDocRange->m_pos1,pDocRange->m_pos2 ));
347 if ((pos >= pDocRange->m_pos1) && (pos <= pDocRange->m_pos2+1))
348 {
349 return true;
350 }
351 }
352 return false;
353
354 }
355
isSelected(void) const356 bool FV_Selection::isSelected(void) const
357 {
358 return FV_SelectionMode_NONE != m_iSelectionMode;
359 }
360
clearSelection(void)361 void FV_Selection::clearSelection(void)
362 {
363 setMode(FV_SelectionMode_NONE);
364 setSelectAll(false);
365 }
366
setTableLayout(fl_TableLayout * pFL)367 void FV_Selection::setTableLayout(fl_TableLayout * pFL)
368 {
369 UT_ASSERT((m_iSelectionMode == FV_SelectionMode_TableColumn)
370 || ( m_iSelectionMode == FV_SelectionMode_TableRow));
371 m_pTableOfSelectedColumn = pFL;
372 }
373
374 /*!
375 * Add a range to the list of selected regions as defined by posLow, posHigh.
376 * If bAddData is true also make a copy of the selected text in RTF format.
377 */
addSelectedRange(PT_DocPosition,PT_DocPosition,bool)378 void FV_Selection::addSelectedRange(PT_DocPosition /*posLow*/, PT_DocPosition /*posHigh*/, bool /*bAddData*/)
379 {
380
381 }
382
383
384 /*!
385 * Add a cell to the list of selected regions.
386 */
addCellToSelection(fl_CellLayout * pCell)387 void FV_Selection::addCellToSelection(fl_CellLayout * pCell)
388 {
389 UT_ASSERT((m_iSelectionMode == FV_SelectionMode_TableColumn)
390 || ( m_iSelectionMode == FV_SelectionMode_TableRow));
391 pf_Frag_Strux* sdhEnd = NULL;
392 pf_Frag_Strux* sdhStart = pCell->getStruxDocHandle();
393 PT_DocPosition posLow = getDoc()->getStruxPosition(sdhStart) +1; // First block
394
395 UT_DebugOnly<bool> bres = getDoc()->getNextStruxOfType(sdhStart,PTX_EndCell,&sdhEnd);
396 PT_DocPosition posHigh = getDoc()->getStruxPosition(sdhEnd) -1;
397 UT_ASSERT(bres && sdhEnd);
398 PD_DocumentRange * pDocRange = new PD_DocumentRange(getDoc(),posLow,posHigh);
399 m_vecSelRanges.addItem(pDocRange);
400 IE_Exp_RTF * pExpRtf = new IE_Exp_RTF(pDocRange->m_pDoc);
401 UT_ByteBuf * pByteBuf = new UT_ByteBuf;
402 if (pExpRtf)
403 {
404 if(posLow < posHigh)
405 {
406 pDocRange->m_pos1++;
407 pDocRange->m_pos2++;
408 }
409 pExpRtf->copyToBuffer(pDocRange,pByteBuf);
410 if(posLow < posHigh)
411 {
412 pDocRange->m_pos1--;
413 pDocRange->m_pos2--;
414 }
415 DELETEP(pExpRtf);
416 }
417 m_vecSelRTFBuffers.addItem(pByteBuf);
418 FV_SelectionCellProps * pCellProps = new FV_SelectionCellProps;
419 UT_sint32 iLeft,iRight,iTop,iBot;
420 m_pView->getCellParams(posLow,&iLeft,&iRight,&iTop,&iBot);
421 UT_DEBUGMSG(("In Selection left %d right %d top %d bot %d \n",iLeft,iRight,iTop,iBot));
422 pCellProps->m_iLeft = iLeft;
423 pCellProps->m_iRight = iRight;
424 pCellProps->m_iTop = iTop;
425 pCellProps->m_iBot = iBot;
426 m_vecSelCellProps.addItem(pCellProps);
427 setSelectAll(false);
428 }
429
430 /*!
431 * Return the ith selection.
432 */
getNthSelection(UT_sint32 i) const433 PD_DocumentRange * FV_Selection::getNthSelection(UT_sint32 i) const
434 {
435 if(i >= getNumSelections())
436 {
437 return NULL;
438 }
439 PD_DocumentRange * pDocRange = m_vecSelRanges.getNthItem(i);
440 return pDocRange;
441 }
442
443 /*!
444 * Return the number of active selections.
445 */
getNumSelections(void) const446 UT_sint32 FV_Selection::getNumSelections(void) const
447 {
448 return m_vecSelRanges.getItemCount();
449 }
450