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