1 /* -*- mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: t -*- */
2 /* AbiWord
3  * Copyright (C) 1998-2000 AbiSource, Inc.
4  * Copyright (c) 2001,2002 Tomas Frydrych
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program 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 General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19  * 02110-1301 USA.
20  */
21 
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25 #define BENCHLAYOUT 0
26 #include <stdlib.h>
27 #include <stdio.h>
28 #include <ctype.h>
29 #include <string.h>
30 #include <locale.h>
31 #include <vector>
32 
33 #include "ut_assert.h"
34 #include "ut_debugmsg.h"
35 #include "ut_go_file.h"
36 #include "ut_growbuf.h"
37 #include "ut_misc.h"
38 #include "ut_string.h"
39 #include "ut_bytebuf.h"
40 #include "ut_timer.h"
41 #include "ut_Language.h"
42 #include "ut_uuid.h"
43 
44 #include "xav_View.h"
45 #include "fl_DocLayout.h"
46 #include "fl_BlockLayout.h"
47 #ifdef ENABLE_SPELL
48 #include "fl_Squiggles.h"
49 #endif
50 #include "fl_SectionLayout.h"
51 #include "fl_AutoNum.h"
52 #include "fp_Page.h"
53 #include "fp_PageSize.h"
54 #include "fp_Column.h"
55 #include "fp_Line.h"
56 #include "fp_Run.h"
57 #include "fp_TextRun.h"
58 #include "fg_Graphic.h"
59 #include "fg_GraphicRaster.h"
60 #include "pd_Document.h"
61 #include "pd_Style.h"
62 #include "pp_Property.h"
63 #include "pp_AttrProp.h"
64 #include "gr_Graphics.h"
65 #include "gr_Painter.h"
66 #include "gr_DrawArgs.h"
67 #include "ie_types.h"
68 #include "xap_App.h"
69 #include "xap_Frame.h"
70 #include "xap_Clipboard.h"
71 #include "ap_TopRuler.h"
72 #include "ap_LeftRuler.h"
73 #include "ap_Prefs.h"
74 #include "ap_Strings.h"
75 #include "fd_Field.h"
76 #include "pf_Frag_Strux.h"
77 #include "fp_FootnoteContainer.h"
78 #include "fv_ViewDoubleBuffering.h"
79 
80 #ifdef ENABLE_SPELL
81 #include "spell_manager.h"
82 #if 1
83 // todo: work around to remove the INPUTWORDLEN restriction for pspell
84 #include "ispell_def.h"
85 #endif
86 #endif
87 
88 #include "ut_rand.h"
89 #include "fp_TableContainer.h"
90 #include "fl_FootnoteLayout.h"
91 #include "fl_ContainerLayout.h"
92 #include "fl_TOCLayout.h"
93 #include "pp_Revision.h"
94 
95 #include "ap_Dialog_SplitCells.h"
96 #include "ev_Mouse.h"
97 #include "fv_View.h"
98 
99 // RIVERA
100 #include "ap_Dialog_Annotation.h"
101 #include "xap_Dialog.h"
102 #include "xap_DialogFactory.h"
103 #include "ap_Dialog_Id.h"
104 
105 // NB -- irrespective of this size, the piecetable will store
106 // at max BOOKMARK_NAME_LIMIT of chars as defined in pf_Frag_Bookmark.h
107 #define BOOKMARK_NAME_SIZE 30
108 #define CHECK_WINDOW_SIZE if(getWindowHeight() < 20) return;
109 #if BENCHLAYOUT
110 #include <time.h>
111 #endif
112 
113 #include "pd_DocumentRDF.h"
114 
115 /****************************************************************/
116 
cmdUnselectSelection(void)117 void FV_View::cmdUnselectSelection(void)
118 {
119 	_clearSelection();
120 }
121 
122 
123 /*!
124   Move point a number of character positions
125   \param bForward True if moving forward
126   \param count Number of char positions to move
127 
128   \note Cursor movement while there's a selection has the effect of
129 		clearing the selection. And only that. See bug 993.
130 */
cmdCharMotion(bool bForward,UT_uint32 count)131 void FV_View::cmdCharMotion(bool bForward, UT_uint32 count)
132 {
133 	if (!isSelectionEmpty())
134 	{
135 		_moveToSelectionEnd(bForward);
136 		_fixInsertionPointCoords();
137 		_ensureInsertionPointOnScreen();
138 		notifyListeners(AV_CHG_MOTION);
139 		return;
140 	}
141 
142 	PT_DocPosition iPoint = getPoint();
143 	if (!_charMotion(bForward, count))
144 	{
145 		if(bForward)
146 		{
147 //
148 // Reached end of document.
149 //
150 			UT_DEBUGMSG(("SEVIOR: Reached end of document \n"));
151 			m_bPointEOL = true;
152 		}
153 		else
154 		{
155 		        if(m_bInsertAtTablePending)
156 			{
157 			      m_iInsPoint = iPoint;
158 			}
159 			else
160 			{
161 			      _setPoint(iPoint);
162 			}
163 		}
164 
165 		bool bOK = true;
166 		while(bOK && !isPointLegal() && (getPoint() > 2))
167 		{
168 			bOK = _charMotion(false,1);
169 		}
170 	}
171 	else
172 	{
173 		PT_DocPosition iPoint1 = getPoint();
174 		if ( iPoint1 == iPoint )
175 		{
176 			if(!_charMotion(bForward, count))
177 			{
178 				_setPoint(iPoint);
179 				_fixInsertionPointCoords();
180 				_ensureInsertionPointOnScreen();
181 				notifyListeners(AV_CHG_MOTION);
182 				return;
183 			}
184 			if(!isPointLegal())
185 			{
186 				_setPoint(iPoint);
187 				_fixInsertionPointCoords();
188 				_ensureInsertionPointOnScreen();
189 				notifyListeners(AV_CHG_MOTION);
190 				return;
191 			}
192 		}
193 	}
194 	_fixInsertionPointCoords();
195 	_ensureInsertionPointOnScreen();
196 	notifyListeners(AV_CHG_MOTION);
197 }
198 
199 
200 /*!
201  * Split the merged cells located at the current point in the way specified
202  * by iSplitType
203   */
cmdSplitCells(AP_CellSplitType iSplitType)204 bool FV_View::cmdSplitCells(AP_CellSplitType iSplitType)
205 {
206 	STD_DOUBLE_BUFFERING_FOR_THIS_FUNCTION
207 
208 	pf_Frag_Strux* cellSDH,*tableSDH,*curSDH,*endTableSDH;
209 	pf_Frag_Strux* prevCellSDH1,*prevCellSDH2;
210 	PT_DocPosition posTable,posCell,posFirstInsert,posEndTable;
211 	posFirstInsert = 0;
212 	UT_sint32 iLeft,iRight,iTop,iBot;
213 	UT_sint32 jLeft,jRight,jTop,jBot;
214 	PT_DocPosition posCol = getPoint();
215 	if(!isInTable(posCol))
216 	{
217 		return false;
218 	}
219 	getCellParams(posCol, &iLeft, &iRight,&iTop,&iBot);
220 	UT_String sCellProps;
221 	getCellFormat(posCol,sCellProps);
222 //
223 // Find the Row and column of the cell at the current point. The strategy
224 // will be insert a new cell with the same (row/col depending on the split)
225 // and to adjust the rest of the table past this point.
226 //
227 	UT_sint32 rowSpan = iBot - iTop;
228 	UT_sint32 colSpan = iRight - iLeft;
229 	bool bRes = m_pDoc->getStruxOfTypeFromPosition(posCol,PTX_SectionCell,&cellSDH);
230 	bRes = m_pDoc->getStruxOfTypeFromPosition(posCol,PTX_SectionTable,&tableSDH);
231 	UT_return_val_if_fail(bRes, false);
232 
233 	posTable = m_pDoc->getStruxPosition(tableSDH) + 1;
234 	posCell = m_pDoc->getStruxPosition(cellSDH);
235 	endTableSDH = m_pDoc->getEndTableStruxFromTableSDH(tableSDH);
236 	posEndTable = m_pDoc->getStruxPosition(endTableSDH);
237 
238 	// Get the attributes and properties of the current block. These attributes and properties
239 	// will be copied in the new cell.
240 	fl_BlockLayout * pBL = getBlockAtPosition(getPoint());
241 	const PP_AttrProp * pAP = NULL;
242 	m_pDoc->getAttrProp(m_pDoc->getAPIFromSDH(pBL->getStruxDocHandle()), &pAP);
243 	UT_return_val_if_fail(pAP, false);
244 
245 //
246 // Got all we need, now set things up to do the insert nicely
247 //
248 	// Signal PieceTable Change
249 	_saveAndNotifyPieceTableChange();
250 
251 	// Turn off list updates
252 
253 	m_pDoc->disableListUpdates();
254 	m_pDoc->beginUserAtomicGlob();
255 	if (!isSelectionEmpty())
256 	{
257 		_clearSelection();
258 	}
259 	m_pDoc->setDontImmediatelyLayout(true);
260 //
261 // Now trigger a rebuild of the whole table by sending a changeStrux to the table strux
262 // with a bogus line-type property. We'll restore it later.
263 //
264 	const char * pszTable[3] = {NULL,NULL,NULL};
265 	pszTable[0] = "list-tag";
266 	const char * szListTag = NULL;
267 	UT_String sListTag;
268 	UT_sint32 iListTag;
269 	m_pDoc->getPropertyFromSDH(tableSDH,isShowRevisions(),getRevisionLevel(),pszTable[0],&szListTag);
270 	if(szListTag == NULL || *szListTag == '\0')
271 	{
272 		iListTag = 0;
273 	}
274 	else
275 	{
276 		iListTag = atoi(szListTag);
277 		iListTag -= 1;
278 	}
279 	UT_String_sprintf(sListTag,"%d",iListTag);
280 	pszTable[1] = sListTag.c_str();
281 	UT_DEBUGMSG(("SEVIOR: Doing Table strux change of %s %s \n",pszTable[0],pszTable[1]));
282 	m_pDoc->changeStruxFmt(PTC_AddFmt,posTable,posTable,NULL,pszTable,PTX_SectionTable);
283 	UT_sint32 splitLeft,splitRight,splitTop,splitBot;
284 	splitLeft = splitRight = 0;
285 	UT_sint32 newLeft,newRight,newTop,newBot;
286 	newTop = newBot = 0;
287 	UT_sint32 numRows = 0;
288 	UT_sint32 numCols = 0;
289 	bool bDoSplitSolidHori = false;
290 	bool bDoSplitSolidVert = false;
291 //
292 // OK now insert the cell and do the update
293 //
294 	m_pDoc-> getRowsColsFromTableSDH(tableSDH, isShowRevisions(), getRevisionLevel(), &numRows, &numCols);
295 
296 	if(iSplitType <= hori_right)
297 	{
298 //
299 // This is similar to "insert column"
300 //
301 		if(iSplitType ==  hori_left)
302 		{
303 			splitLeft = iLeft;
304 			splitRight = iLeft+1;
305 		}
306 		else if(iSplitType ==  hori_mid)
307 		{
308 			splitLeft = iLeft;
309 			if(colSpan == 1)
310 			{
311 				bDoSplitSolidHori = true;
312 				splitRight = iLeft+1;
313 			}
314 			else
315 			{
316 				splitRight = iLeft + colSpan/2;
317 			}
318 		}
319 		else if(iSplitType ==  hori_right)
320 		{
321 			splitLeft = iLeft;
322 			splitRight = iRight -1;
323 		}
324 		splitTop = iTop;
325 		splitBot = iBot;
326 		newTop = iTop;
327 		newBot = iBot;
328 		if(!bDoSplitSolidHori)
329 		{
330 			newLeft = splitRight;
331 			newRight = iRight;
332 		}
333 		else
334 		{
335 			newLeft = splitRight;
336 			newRight = newLeft+1;
337 		}
338 
339 	}
340 	else
341 	{
342 		if(iSplitType ==  vert_above)
343 		{
344 			newTop = iTop;
345 			newBot = iTop +1;
346 		}
347 		else if(iSplitType ==  vert_mid)
348 		{
349 			newTop = iTop;
350 			if(rowSpan == 1)
351 			{
352 				bDoSplitSolidVert = true;
353 				newBot = newTop+1;
354 			}
355 			else
356 			{
357 				newBot = iTop + rowSpan/2;
358 			}
359 		}
360 		else if(iSplitType ==  vert_below)
361 		{
362 			newTop = iTop;
363 			newBot = iBot -1;
364 		}
365 //
366 // we need to get the location of where to place this cell.
367 //
368 		splitLeft = iLeft;
369 		splitRight = iRight;
370 		newLeft = iLeft;
371 		newRight = iRight;
372 		if(!bDoSplitSolidVert)
373 		{
374 			splitTop = newBot;
375 			splitBot = iBot;
376 		}
377 		else
378 		{
379 			newTop = iTop;
380 			newBot = newTop+1;
381 			splitTop = newBot;
382 			splitBot = splitTop+1;
383 		}
384 //
385 // OK now we have to find the place to insert this. It should be the cell
386 // immediately after (splitTop,splitLeft)
387 //
388 //(except if it's a splitSolidVert in which case it should be placed as the
389 // next next on the row in the first cell before (splitleft,splittop)
390 //
391 		if(bDoSplitSolidVert)
392 		{
393 //
394 // OK start with cellSDH and scan until we either reach the end of the table
395 // or we find a cell past where splitcell should be. Then we insert the cell
396 // at where cell just after splitcell is.
397 //
398 			bool bStop = false;
399 			curSDH = cellSDH;
400 			while(!bStop)
401 			{
402 				posCell = m_pDoc->getStruxPosition(curSDH)+1;
403 				bRes = getCellParams(posCell,&jLeft,&jRight,&jTop,&jBot);
404 				UT_ASSERT(bRes);
405 				if(jTop >= splitTop)
406 				{
407 //
408 // Found it!
409 //
410 					bStop = true;
411 					posCell = m_pDoc->getStruxPosition(curSDH);
412 					break;
413 				}
414 				bRes = m_pDoc->getNextStruxOfType(curSDH,PTX_SectionCell,&curSDH);
415 				if(!bRes)
416 				{
417 					bStop = true;
418 					posCell = m_pDoc->getStruxPosition(endTableSDH);
419 					break;
420 				}
421 				posCell = m_pDoc->getStruxPosition(curSDH);
422 				if(posCell > posEndTable)
423 				{
424 					bStop = true;
425 					posCell = m_pDoc->getStruxPosition(endTableSDH);
426 					break;
427 				}
428 			}
429 		}
430 		else
431 		{
432 			jTop = splitTop;
433 			jBot = jTop+1;
434 			jLeft = splitRight;
435 			if(jLeft >= numCols)
436 			{
437 				jLeft = 0;
438 				jTop += 1;
439 				jBot +=1;
440 			}
441 			jRight = jLeft+1;
442 			if(jTop >= numRows)
443 			{
444 //
445 // Place right before endTable Strux
446 //
447 				if(endTableSDH == NULL)
448 				{
449 					//
450 					// Disaster! the table structure in the piecetable is screwed.
451 					// we're totally stuffed now.
452 					UT_ASSERT(UT_SHOULD_NOT_HAPPEN);
453 					return false;
454 				}
455 				posCell = m_pDoc->getStruxPosition(endTableSDH);
456 			}
457 			else
458 			{
459 //
460 // now we have to loop until we find a cell precisely at jLeft,jTop
461 //
462 				bool bFound = false;
463 				while(!bFound)
464 				{
465 					curSDH = m_pDoc-> getCellSDHFromRowCol(tableSDH,isShowRevisions(), getRevisionLevel(), jTop,jLeft);
466 					if(curSDH == NULL)
467 					{
468 						endTableSDH = m_pDoc->getEndTableStruxFromTableSDH(tableSDH);
469 						if(endTableSDH == NULL)
470 						{
471 							//
472 							// Disaster! the table structure in the piecetable is screwed.
473 							// we're totally stuffed now.
474 							UT_ASSERT(UT_SHOULD_NOT_HAPPEN);
475 							return false;
476 						}
477 						posCell = m_pDoc->getStruxPosition(endTableSDH);
478 						bFound = true;
479 					}
480 					UT_sint32 kLeft,kRight,kTop,kBot;
481 					PT_DocPosition posTmp = m_pDoc->getStruxPosition(curSDH)+1;
482 					getCellParams(posTmp,&kLeft,&kRight,&kTop,&kBot);
483 					if((kLeft == jLeft) && (kTop == jTop))
484 					{
485 						bFound = true;
486 						posCell = m_pDoc->getStruxPosition(curSDH);
487 					}
488 					else
489 					{
490 						jLeft++;
491 						jRight++;
492 						if(jLeft >= numCols)
493 						{
494 							jLeft = 0;
495 							jTop++;
496 							jRight =1;
497 							jBot++;
498 						}
499 						if(jTop >= numRows)
500 						{
501 							endTableSDH = m_pDoc->getEndTableStruxFromTableSDH(tableSDH);
502 							if(endTableSDH == NULL)
503 							{
504 								//
505 								// Disaster! the table structure in the piecetable is screwed.
506 								// we're totally stuffed now.
507 								UT_ASSERT(UT_SHOULD_NOT_HAPPEN);
508 								return false;
509 							}
510 							posCell = m_pDoc->getStruxPosition(endTableSDH);
511 							bFound = true;
512 						}
513 					}
514 				}
515 			}
516 		}
517 	}
518 //
519 // OK build the table properties
520 //
521 	UT_String sRowTop = "top-attach";
522 	UT_String sRowBot = "bot-attach";
523 	UT_String sColLeft = "left-attach";
524 	UT_String sColRight = "right-attach";
525 	UT_String sTop,sBot,sLeft,sRight;
526 	UT_String_sprintf(sTop,"%d",splitTop);
527 	UT_String_sprintf(sBot,"%d",splitBot);
528 	UT_String_sprintf(sLeft,"%d",splitLeft);
529 	UT_String_sprintf(sRight,"%d",splitRight);
530 	UT_String_setProperty(sCellProps,sRowTop,sTop);
531 	UT_String_setProperty(sCellProps,sRowBot,sBot);
532 	UT_String_setProperty(sCellProps,sColLeft,sLeft);
533 	UT_String_setProperty(sCellProps,sColRight,sRight);
534 	UT_DEBUGMSG(("Cells props for new cell:\n  %s \n",sCellProps.c_str()));
535 //
536 // Insert the cell
537 //
538 	const gchar * atts[4] = {"props",NULL,NULL,NULL};
539 	atts[1] = sCellProps.c_str();
540 	bRes = m_pDoc->insertStrux(posCell,PTX_SectionCell,atts,NULL);
541 	bRes = m_pDoc->insertStrux(posCell+1,PTX_Block,pAP->getAttributes(),pAP->getProperties());
542 	posFirstInsert = posCell + 2;
543 //
544 // Save the cell SDH for later..
545 //
546 	m_pDoc->getStruxOfTypeFromPosition(posCell+1,PTX_SectionCell,&prevCellSDH1);
547 
548 	bRes = m_pDoc->insertStrux(posCell+2,PTX_EndCell);
549 
550 // Changes the props of the new cell
551 	UT_String_sprintf(sTop,"%d",newTop);
552 	UT_String_sprintf(sBot,"%d",newBot);
553 	UT_String_sprintf(sLeft,"%d",newLeft);
554 	UT_String_sprintf(sRight,"%d",newRight);
555 	UT_String_setProperty(sCellProps,sRowTop,sTop);
556 	UT_String_setProperty(sCellProps,sRowBot,sBot);
557 	UT_String_setProperty(sCellProps,sColLeft,sLeft);
558 	UT_String_setProperty(sCellProps,sColRight,sRight);
559 	posCell = m_pDoc->getStruxPosition(cellSDH)+1;
560 	UT_DEBUGMSG(("New Cells props for old cell:\n  %s \n",sCellProps.c_str()));
561 	atts[1] = sCellProps.c_str();
562 	UT_DebugOnly<bool> bres = m_pDoc->changeStruxFmt(PTC_AddFmt,posCell,posCell,atts,NULL,PTX_SectionCell);
563 	UT_ASSERT(bres);
564 	m_pDoc->getStruxOfTypeFromPosition(posCell,PTX_SectionCell,&prevCellSDH2);		if(bDoSplitSolidHori)
565 	{
566 //
567 // OK now we have to adjust all the cells with left or right >= splitleft
568 // If left of a given cell is < splitLeft it is not adjusted but the right
569 // of the cell if it's > splitleft is incremented. In this way our new cell
570 // span two columns
571 //
572 		UT_sint32 myleft,myright,mytop,mybot;
573 //
574 // start at the first cell and scan through the table adjusting each cell.
575 //
576 		bres = m_pDoc->getStruxOfTypeFromPosition(posTable+1,PTX_SectionCell,&cellSDH);
577 		UT_ASSERT(bres);
578 		bool bStop= false;
579 		while(!bStop)
580 		{
581 			posCell = m_pDoc->getStruxPosition(cellSDH)+1;
582 			bres = getCellParams(posCell,&myleft,&myright,&mytop,&mybot);
583 			UT_ASSERT(bres);
584 			bool bChange =false;
585 			if((cellSDH == prevCellSDH1) || (cellSDH == prevCellSDH2))
586 			{
587 //
588 // Igore me!
589 //
590 				bChange = false;
591 			}
592 			else
593 			{
594 				if(myright> splitLeft)
595 				{
596 					myright++;
597 					bChange = true;
598 				}
599 				if(myleft>splitLeft)
600 				{
601 					myleft++;
602 					bChange = true;
603 				}
604 				if(bChange)
605 				{
606 // Changes the props of the cell
607 					UT_String_sprintf(sTop,"%d",mytop);
608 					UT_String_sprintf(sBot,"%d",mybot);
609 					UT_String_sprintf(sLeft,"%d",myleft);
610 					UT_String_sprintf(sRight,"%d",myright);
611 					UT_String_setProperty(sCellProps,sRowTop,sTop);
612 					UT_String_setProperty(sCellProps,sRowBot,sBot);
613 					UT_String_setProperty(sCellProps,sColLeft,sLeft);
614 					UT_String_setProperty(sCellProps,sColRight,sRight);
615 					atts[1] = sCellProps.c_str();
616 					m_pDoc->changeStruxFmt(PTC_AddFmt,posCell,posCell,atts,NULL,PTX_SectionCell);
617 				}
618 			}
619 			if(!m_pDoc->getNextStruxOfType(cellSDH,PTX_SectionCell,&cellSDH))
620 			{
621 				bStop = true;
622 				break;
623 			}
624 			posCell = m_pDoc->getStruxPosition(cellSDH);
625 			if(posCell > posEndTable)
626 			{
627 				bStop = true;
628 				break;
629 			}
630 		}
631 	}
632 	if(bDoSplitSolidVert)
633 	{
634 //
635 // OK now we have to adjust all the cells with top or bot >= newTop
636 // If top of a given cell is < newTop it is not adjusted but the bot
637 // of the cell if it's > newTop is incremented. In this way our new cell
638 // spans two rows
639 //
640 		UT_sint32 myleft,myright,mytop,mybot;
641 //
642 // start at the first cell and scan through the table adjusting each cell.
643 //
644 		m_pDoc->getStruxOfTypeFromPosition(posTable+1,PTX_SectionCell,&cellSDH);
645 		bool bStop= false;
646 		while(!bStop)
647 		{
648 			posCell = m_pDoc->getStruxPosition(cellSDH) +1;
649 			getCellParams(posCell,&myleft,&myright,&mytop,&mybot);
650 			bool bChange =false;
651 			if((cellSDH == prevCellSDH1) || (cellSDH == prevCellSDH2))
652 			{
653 //
654 // Igore me!
655 //
656 				bChange = false;
657 			}
658 			else
659 			{
660 				if(mytop>newTop)
661 				{
662 					mytop++;
663 					bChange = true;
664 				}
665 				if(mybot>newTop)
666 				{
667 					mybot++;
668 					bChange = true;
669 				}
670 				if(bChange)
671 				{
672 // Changes the props of the cell
673 					UT_String_sprintf(sTop,"%d",mytop);
674 					UT_String_sprintf(sBot,"%d",mybot);
675 					UT_String_sprintf(sLeft,"%d",myleft);
676 					UT_String_sprintf(sRight,"%d",myright);
677 					UT_String_setProperty(sCellProps,sRowTop,sTop);
678 					UT_String_setProperty(sCellProps,sRowBot,sBot);
679 					UT_String_setProperty(sCellProps,sColLeft,sLeft);
680 					UT_String_setProperty(sCellProps,sColRight,sRight);
681 					atts[1] = sCellProps.c_str();
682 					m_pDoc->changeStruxFmt(PTC_AddFmt,posCell,posCell,atts,NULL,PTX_SectionCell);
683 				}
684 			}
685 			if(!m_pDoc->getNextStruxOfType(cellSDH,PTX_SectionCell,&cellSDH))
686 			{
687 				bStop = true;
688 				break;
689 			}
690 			posCell = m_pDoc->getStruxPosition(cellSDH);
691 			if(posCell > posEndTable)
692 			{
693 				bStop = true;
694 				break;
695 			}
696 		}
697 	}
698 
699 //
700 // Now trigger a rebuild of the whole table by sending a changeStrux to the table strux
701 // with the restored line-type property it has before.
702 //
703 	iListTag += 1;
704 	UT_String_sprintf(sListTag,"%d",iListTag);
705 	pszTable[1] = sListTag.c_str();
706 	UT_DEBUGMSG(("SEVIOR: Doing Table strux change of %s %s \n",pszTable[0],pszTable[1]));
707 	m_pDoc->changeStruxFmt(PTC_AddFmt,posTable,posTable,NULL,pszTable,PTX_SectionTable);
708 //
709 // OK finish everything off with the various parameters which allow the formatter to
710 // be updated.
711 //
712 	m_pDoc->setDontImmediatelyLayout(false);
713 
714 	// Signal PieceTable Changes have finished
715 	_restorePieceTableState();
716 	_generalUpdate();
717 
718 	m_pDoc->endUserAtomicGlob();
719 
720 	// restore updates and clean up dirty lists
721 	m_pDoc->enableListUpdates();
722 	m_pDoc->updateDirtyLists();
723 // Put the insertion point in a legal position
724 //
725 	setPoint(posFirstInsert);
726 	_fixInsertionPointCoords();
727 	_ensureInsertionPointOnScreen();
728 	notifyListeners(AV_CHG_MOTION);
729 	return true;
730 }
731 
cmdSelectTOC(UT_sint32 x,UT_sint32 y)732 void  FV_View::cmdSelectTOC(UT_sint32 x, UT_sint32 y)
733 {
734 	UT_sint32 xClick=0,yClick = 0;
735 	fp_Page* pPage = _getPageForXY(x,y,xClick,yClick);
736 	fl_TOCLayout * pTOCL = pPage->getLastMappedTOC();
737 	UT_return_if_fail(pTOCL);
738 	m_Selection.setTOCSelected(pTOCL);
739 	PT_DocPosition pos = pTOCL->getPosition();
740 	m_iInsPoint = pos+1;
741 	if(m_pG)
742 	{
743 		m_pG->allCarets()->disable();
744 	}
745 	m_countDisable++;
746 }
747 
748 /*!
749  * Select the column of the table  identified by the document position
750  * posOfColumn
751  */
cmdSelectColumn(PT_DocPosition posOfColumn)752 bool FV_View::cmdSelectColumn(PT_DocPosition posOfColumn)
753 {
754 	pf_Frag_Strux* cellSDH,*tableSDH;
755 	PT_DocPosition posTable;
756 	UT_sint32 iLeft,iRight,iTop,iBot;
757 	UT_sint32 Left,Right,Top,Bot;
758 	bool bEOL = false; // added this stop compiler warning. Tomas
759 	if(!isInTable(posOfColumn))
760 	{
761 		return false;
762 	}
763 	if(!isSelectionEmpty())
764 	{
765 		_clearSelection();
766 		_resetSelection();
767 	}
768 	getCellParams(posOfColumn, &iLeft, &iRight,&iTop,&iBot);
769 	bool bRes = m_pDoc->getStruxOfTypeFromPosition(posOfColumn,PTX_SectionCell,&cellSDH);
770 	bRes = m_pDoc->getStruxOfTypeFromPosition(posOfColumn,PTX_SectionTable,&tableSDH);
771 	UT_return_val_if_fail(bRes, false);
772 
773 	posTable = m_pDoc->getStruxPosition(tableSDH) + 1;
774 
775 //
776 // Now find the number of rows and columns inthis table.
777 //
778 	UT_sint32 numRows = 0;
779 	UT_sint32 numCols = 0;
780 	m_pDoc->getRowsColsFromTableSDH(tableSDH, isShowRevisions(), getRevisionLevel(), &numRows, &numCols);
781 //
782 // Ok set the selection type to that of a column
783 //
784 	m_Selection.setMode(FV_SelectionMode_TableColumn);
785 
786 	fl_BlockLayout * pBlock = NULL;
787 	fp_Run * pRun = NULL;
788 	UT_sint32 xCaret, yCaret;
789 	UT_uint32 heightCaret;
790 	UT_sint32 xCaret2, yCaret2;
791 	bool bDirection;
792 	_findPositionCoords(posOfColumn, bEOL, xCaret, yCaret, xCaret2, yCaret2, heightCaret, bDirection, &pBlock, &pRun);
793 	UT_return_val_if_fail(pBlock,false);
794 	fl_ContainerLayout * pCL2 = pBlock->myContainingLayout();
795 	UT_return_val_if_fail(pCL2,false);
796 	pCL2 = pCL2->myContainingLayout();
797 	UT_return_val_if_fail(pCL2,false);
798 	UT_return_val_if_fail((pCL2->getContainerType() == FL_CONTAINER_TABLE),false);
799 	fl_TableLayout * pTL = static_cast<fl_TableLayout *>(pCL2);
800 	m_Selection.setTableLayout(pTL);
801 //
802 // Now loop through the column and collect all the cells.
803 //
804 	UT_sint32 j = 0;
805 	UT_sint32 jPrev = -1;
806 	for(j=0; j<numRows; j++)
807 	{
808 		PT_DocPosition posWork = findCellPosAt(posTable,j,iLeft) +1;
809 		getCellParams(posWork,&Left,&Right,&Top,&Bot);
810 		UT_DEBUGMSG(("Adding cell at left %d right %d top %d bot %d posWork %d \n",Left,Right,Top,Bot,posWork));
811 		if(Top == jPrev)
812 		{
813 			continue;
814 		}
815 		_findPositionCoords(posWork+1, bEOL, xCaret, yCaret, xCaret2, yCaret2, heightCaret, bDirection, &pBlock, &pRun);
816 		UT_return_val_if_fail(pBlock,false);
817 		UT_DEBUGMSG(("Block pos = %d \n",pBlock->getPosition(false)));
818 		fl_ContainerLayout * pCL = pBlock->myContainingLayout();
819 		UT_return_val_if_fail((pCL->getContainerType() == FL_CONTAINER_CELL),false);
820 		fl_CellLayout * pCell = static_cast<fl_CellLayout *>(pCL);
821 		m_Selection.addCellToSelection(pCell);
822 		jPrev = j;
823 	}
824 	PD_DocumentRange * pRange = getNthSelection(getNumSelections()-1);
825 	_setPoint(pRange->m_pos2);
826 	_drawSelection();
827 	notifyListeners(AV_CHG_MOTION);
828 	return true;
829 }
830 
831 /*!
832  * Convert a table to Text with each cell separated by commas, Tabs,
833  * or tabs and commas as follows:
834  * iSepType == 0 Use Commas
835  * iSepType == 1 Use Tabs
836  * iSepType == 2 Use Tabs and Commas
837  * We place a paragraph break at the end of of each row but otherwise we simply
838  * extract just the text from each cell.
839  */
cmdTableToText(PT_DocPosition posSource,UT_sint32 iSepType)840 bool FV_View::cmdTableToText(PT_DocPosition posSource,UT_sint32 iSepType)
841 {
842 	fl_TableLayout * pTL = getTableAtPos(posSource);
843 	UT_return_val_if_fail(pTL,false);
844 	if (!isSelectionEmpty())
845 	{
846 		_clearSelection();
847 	}
848 
849   	pf_Frag_Strux* tableSDH;
850 	bool bRes = m_pDoc->getStruxOfTypeFromPosition(posSource,PTX_SectionTable,&tableSDH);
851 	UT_return_val_if_fail(bRes, false);
852 	PT_DocPosition posTable = m_pDoc->getStruxPosition(tableSDH) + 1;
853 
854 //
855 // Now find the number of rows and columns inthis table.
856 //
857 	UT_sint32 numRows = 0;
858 	UT_sint32 numCols = 0;
859 	m_pDoc->getRowsColsFromTableSDH(tableSDH, isShowRevisions(), getRevisionLevel(), &numRows, &numCols);
860 	PT_DocPosition posInsert = pTL->getPosition(true);
861 
862 	// Signal PieceTable Changes
863 	_saveAndNotifyPieceTableChange();
864 
865 	// Turn off list updates
866 
867 	m_pDoc->disableListUpdates();
868 	m_pDoc->beginUserAtomicGlob();
869 	setPoint(posInsert);
870 	insertParagraphBreak();
871 
872 	UT_sint32 i,j =0;
873 	fp_TableContainer * pTAB = static_cast<fp_TableContainer *>(pTL->getFirstContainer());
874 	fp_CellContainer * pCCell = NULL;
875 	fl_CellLayout * pCellL = NULL;
876 	UT_GrowBufElement iComma = static_cast<UT_GrowBufElement>(',');
877 	UT_GrowBufElement iTab = static_cast<UT_GrowBufElement>(UCS_TAB);
878 	for(i=0;i<numRows;i++)
879 	{
880 	  for(j=0; j< numCols;j++)
881 	  {
882 	    pCCell = pTAB->getCellAtRowColumn(i,j);
883 	    if(pCCell == NULL)
884 	    {
885 	         continue;
886 	    }
887 	    pCellL = static_cast<fl_CellLayout *>(pCCell->getSectionLayout());
888 	    if(pCellL == NULL)
889 	    {
890 	         continue;
891 	    }
892 	    UT_GrowBuf buf;
893 	    buf.truncate(0);
894 	    pCellL->appendTextToBuf(buf);
895 		if (j < numCols - 1)
896 		{
897 			switch (iSepType)
898 			{
899 			case 0:
900 				buf.append(&iComma,1);
901 				break;
902 			case 1:
903 				buf.append(&iTab,1);
904 				break;
905 			default:
906 				buf.append(&iTab,1);
907 				buf.append(&iComma,1);
908 			}
909 		}
910 		if (buf.getPointer(0))
911 		{
912 			cmdCharInsert(reinterpret_cast<UT_UCSChar *>(buf.getPointer(0)),buf.getLength());
913 		}
914 	  }
915 	  if (i < numRows - 1)
916 	  {
917 		  insertParagraphBreak();
918 	  }
919 	}
920 	posTable = pTL->getPosition(true) + 2;
921 	cmdDeleteTable(posTable, true);
922 
923 	// Signal PieceTable Changes have finished
924 	_restorePieceTableState();
925 	_generalUpdate();
926 	m_pDoc->endUserAtomicGlob();
927 
928 
929 	// restore updates and clean up dirty lists
930 	m_pDoc->enableListUpdates();
931 	m_pDoc->updateDirtyLists();
932 	_fixInsertionPointCoords();
933 	_ensureInsertionPointOnScreen();
934 	notifyListeners(AV_CHG_MOTION);
935 	return true;
936 }
937 
938 /*!
939  * Merge the cells located at posSource with posDestination by copying the data from
940  * source to destination. Then deleting source and expanding destination into it's location
941  * in the table.
942  */
cmdMergeCells(PT_DocPosition posSource,PT_DocPosition posDestination)943 bool FV_View::cmdMergeCells(PT_DocPosition posSource, PT_DocPosition posDestination)
944 {
945 	STD_DOUBLE_BUFFERING_FOR_THIS_FUNCTION
946 
947 	UT_sint32 sLeft,sRight,sTop,sBot;
948 	UT_sint32 dLeft,dRight,dTop,dBot;
949 	UT_sint32 Left,Right,Top,Bot; // need these for working variables.
950 	getCellParams(posSource,&sLeft,&sRight,&sTop,&sBot);
951 	getCellParams(posDestination,&dLeft,&dRight,&dTop,&dBot);
952 
953 	PT_DocPosition posTable,posWork;
954 	pf_Frag_Strux* tableSDH;
955 	bool bRes = m_pDoc->getStruxOfTypeFromPosition(posSource,PTX_SectionTable,&tableSDH);
956 	UT_return_val_if_fail(bRes, false);
957 	posTable = m_pDoc->getStruxPosition(tableSDH) + 1;
958 
959 //
960 // Now find the number of rows and columns inthis table.
961 //
962 	UT_sint32 numRows = 0;
963 	UT_sint32 numCols = 0;
964 	m_pDoc->getRowsColsFromTableSDH(tableSDH, isShowRevisions(), getRevisionLevel(), &numRows, &numCols);
965 	bool bChanged = false;
966 	UT_sint32 iLineType = 0;
967 
968 //
969 // Got all we need, now set things up to do the merge nicely
970 //
971 //
972 // OK that's done, now do the merge
973 //
974 // Have to worry about merging cell spanning multiple rows and columns. We do this
975 // by matching the  the widths and heights of the source and destination cells.
976 //
977 	if((sLeft == dLeft) && (sTop == dTop))
978 	{
979 		UT_ASSERT(UT_SHOULD_NOT_HAPPEN);
980 		return false;
981 	}
982 
983 	if(sLeft == dLeft)
984 	{
985 //
986 // Merge vertically
987 //
988 //  might have  d |  |  |  |
989 //                ----------
990 //             s  |        |
991 // To solve this merge all top cells horizontally then merge this combined set vertically
992 //
993 // First check that top row ends at bottom row boundary. We reject attempts to merge cells
994 // like this
995 //            d  |  |  |    |
996 //               ------------
997 //            s  |        |
998 		if(sRight >= dRight)
999 		{
1000 			if(sRight < numCols -1)
1001 			{
1002 				posWork = findCellPosAt(posTable,dTop,sRight) +1;
1003 				getCellParams(posWork,&Left,&Right,&Top,&Bot);
1004 				if(Left != sRight)
1005 				{
1006 					//
1007 					// Right column of src cell doesn't match the row above it. Bail out.
1008 					//
1009 					// fixme: Put in a dialog to explain this to the user
1010 					//
1011 					return false;
1012 				}
1013 			}
1014 			//
1015 			// OK now merge all the cells in the destination cell together.
1016 			//
1017 			Left = dRight;
1018 			while(Left < sRight)
1019 			{
1020 				posWork = findCellPosAt(posTable,dTop,Left) +1;
1021 				getCellParams(posWork,&Left,&Right,&Top,&Bot);
1022 //
1023 // Do the merge without all the undo/update trimings
1024 // append onto destination
1025 				if(!bChanged)
1026 				{
1027 					iLineType = _changeCellParams(posTable, tableSDH);
1028 				}
1029 				bChanged = true;
1030 				_MergeCells(posDestination,posWork,false);
1031 				Left = Right;
1032 			}
1033 //
1034 // Now merge the merged destination into the source
1035 //
1036 			if(!bChanged)
1037 			{
1038 				iLineType = _changeCellParams(posTable, tableSDH);
1039 			}
1040 			bChanged = true;
1041 			posSource = findCellPosAt(posTable,sTop,sLeft) +1;
1042 			posDestination = findCellPosAt(posTable,dTop,dLeft) +1;
1043 			_MergeCells(posDestination,posSource,true);
1044 		}
1045 		else
1046 		{
1047 //
1048 // Here we have this scenario:
1049 //
1050 //             d |          |
1051 //               ------------
1052 //            s  |  |  |    |
1053 //
1054 // ie destination is narrower than the source
1055 //
1056 //			check that the source column lines up with the destination column.
1057 //
1058 			if(dRight < numCols -1)
1059 			{
1060 				posWork = findCellPosAt(posTable,sTop,dRight) +1;
1061 				getCellParams(posWork,&Left,&Right,&Top,&Bot);
1062 				if(Left != dRight)
1063 				{
1064 					//
1065 					// Right column of src cell doesn't match the row above it. Bail out.
1066 					// fixme: Put in a dialog to explain this to the user
1067 					//
1068 					return false;
1069 				}
1070 			}
1071 			//
1072 			// OK now merge all the cells in the src cell together.
1073 			//
1074 			Left = sRight;
1075 			while(Left < dRight)
1076 			{
1077 				posWork = findCellPosAt(posTable,sTop,Left) +1;
1078 				getCellParams(posWork,&Left,&Right,&Top,&Bot);
1079 //
1080 // Do the merge without all the undo/update trimings
1081 //
1082 				if(!bChanged)
1083 				{
1084 					iLineType = _changeCellParams(posTable, tableSDH);
1085 				}
1086 				bChanged = true;
1087 				_MergeCells(posSource,posWork,false);
1088 				Left = Right;
1089 			}
1090 //
1091 // Now merge the merged destination into the source
1092 //
1093 			if(!bChanged)
1094 			{
1095 				iLineType = _changeCellParams(posTable, tableSDH);
1096 			}
1097 			bChanged = true;
1098 			posSource = findCellPosAt(posTable,sTop,sLeft) +1;
1099 			posDestination = findCellPosAt(posTable,dTop,dLeft) +1;
1100 			_MergeCells(posDestination,posSource,true);
1101 		}
1102 	}
1103 	else if(sTop == dTop)
1104 	{
1105 //
1106 // Merge horizontally
1107 //
1108 //  might have  rows spanning several columns
1109 //      d    s
1110 //     ---------
1111 //     |   |   |
1112 //     |   -----
1113 //     |   |   |
1114 //     |   -----
1115 //     |   |   |
1116 //     ---------
1117 // To solve this merge all cells vertically then merge this combined set horizontally
1118 //
1119 // First check that left column ends at right column boundary.
1120 // We reject attempts to merge cells that don't have this condition.
1121 // ie this:
1122 //      d    s
1123 //     ---------
1124 //     |   |   |
1125 //     |   -----
1126 //     |   |   |
1127 //     |   -----
1128 //     |   |   |
1129 //     |   -----
1130 //     |---|   |
1131 //     |   -----
1132 //
1133 		if(dBot >= sBot)
1134 		{
1135 			if(dBot < numRows -1)
1136 			{
1137 				posWork = findCellPosAt(posTable,dBot,sLeft) +1;
1138 				getCellParams(posWork,&Left,&Right,&Top,&Bot);
1139 				if(Top != dBot)
1140 				{
1141 					//
1142 					// Bot col of src cell doesn't match the column before. Bail out.
1143 					//
1144 					// fixme: Put in a dialog to explain this to the user
1145 					//
1146 					return false;
1147 				}
1148 			}
1149 			//
1150 			// OK now merge all the cells right of the src cell together.
1151 			//
1152 			Bot	 = sBot;
1153 			Top = sBot;
1154 			while(Top < dBot)
1155 			{
1156 				posWork = findCellPosAt(posTable,Top,sLeft) +1;
1157 				getCellParams(posWork,&Left,&Right,&Top,&Bot);
1158 //
1159 // Do the merge without all the undo/update trimings
1160 //
1161 				if(!bChanged)
1162 				{
1163 					iLineType = _changeCellParams(posTable, tableSDH);
1164 				}
1165 				bChanged = true;
1166 				_MergeCells(posSource,posWork,false);
1167 				UT_ASSERT(Bot > Top);
1168 				if(Bot <= Top)
1169 				{
1170 					break;
1171 				}
1172 				Top = Bot;
1173 			}
1174 //
1175 // Now merge the merged destination into the source
1176 //
1177 			if(!bChanged)
1178 			{
1179 				iLineType = _changeCellParams(posTable, tableSDH);
1180 			}
1181 			bChanged = true;
1182 			posSource = findCellPosAt(posTable,sTop,sLeft) +1;
1183 			posDestination = findCellPosAt(posTable,dTop,dLeft) +1;
1184 			_MergeCells(posDestination,posSource,true);
1185 		}
1186 		else
1187 		{
1188 //
1189 // Here we have this scenario:
1190 //
1191 //
1192 //  might have  rows spanning several columns
1193 //      d    s
1194 //     ---------
1195 //     |   |   |
1196 //     -----   |
1197 //     |   |   |
1198 //     -----   |
1199 //     |   |   |
1200 //     ---------
1201 // To solve this merge all cells vertically then merge this combined set horizontally
1202 //
1203 // First check that left column ends at right column boundary.
1204 // We reject attempts to merge cells that don't have this condition.
1205 // ie this:
1206 //      d    s
1207 //     ---------
1208 //     |   |   |
1209 //     ----|   |
1210 //     |   |   |
1211 //     ----|   |
1212 //     |   |   |
1213 //     |   |   |
1214 //     |---|   |
1215 //     |   -----
1216 //
1217 
1218 			if(sBot < numRows -1)
1219 			{
1220 				posWork = findCellPosAt(posTable,sBot,dLeft) +1;
1221 				getCellParams(posWork,&Left,&Right,&Top,&Bot);
1222 				if(Top != sBot)
1223 				{
1224 					//
1225 					// Right column of src cell doesn't match the row above it. Bail out.
1226 					//
1227 					// fixme: Put in a dialog to explain this to the user
1228 					//
1229 					return false;
1230 				}
1231 			}
1232 			//
1233 			// OK now merge all the cells above the src cell together.
1234 			//
1235 			Top = dBot;
1236 			while(Top < sBot)
1237 			{
1238 				posWork = findCellPosAt(posTable,Top,dLeft) + 1;
1239 				getCellParams(posWork,&Left,&Right,&Top,&Bot);
1240 //
1241 // Do the merge without all the undo/update trimings
1242 //
1243 				if(!bChanged)
1244 				{
1245 					iLineType = _changeCellParams(posTable, tableSDH);
1246 				}
1247 				bChanged = true;
1248 				_MergeCells(posDestination,posWork,false);
1249 				Top = Bot;
1250 			}
1251 //
1252 // Now merge the source into the merged destination
1253 //
1254 			if(!bChanged)
1255 			{
1256 				iLineType = _changeCellParams(posTable, tableSDH);
1257 			}
1258 			bChanged = true;
1259 			posSource = findCellPosAt(posTable,sTop,sLeft) +1;
1260 			posDestination = findCellPosAt(posTable,dTop,dLeft) +1;
1261 			_MergeCells(posDestination,posSource,true);
1262 		}
1263 	}
1264 	else
1265 	{
1266 //
1267 // Neight left or top align of the cells to be merged.
1268 // bali out
1269 
1270 		return false;
1271 	}
1272 //
1273 // Now check if we've merged a whole row of height 2 or a whole col of width two//
1274 // Start with whole row.
1275 //
1276 	posDestination = findCellPosAt(posTable,dTop,dLeft) +2;
1277 	getCellParams(posDestination,&dLeft,&dRight,&dTop,&dBot);
1278 	UT_sint32 origTop = dTop;
1279 	if((dLeft==0) && (dRight== numCols))
1280 	{
1281 //
1282 // Yep one whole row merged.
1283 //
1284 // Look for the number of rows spanned now
1285 //
1286 		if(dBot > (dTop+1))
1287 		{
1288 //
1289 // Yep we have problem, we'll fix it. Subtract this number from all the cells
1290 // top and Bottom attach
1291 //
1292 			UT_sint32 diff = dBot - dTop -1;
1293 			pf_Frag_Strux* sdhCell = NULL;
1294 			pf_Frag_Strux* sdhNextCell = NULL;
1295 			pf_Frag_Strux* sdhEndTable = NULL;
1296 			PT_DocPosition posEndTable = 0;
1297 			PT_DocPosition posCell = 0;
1298 			bRes = m_pDoc->getStruxOfTypeFromPosition(posDestination,PTX_SectionCell,&sdhCell);
1299 			UT_return_val_if_fail(bRes,false);
1300 			sdhEndTable = m_pDoc->getEndTableStruxFromTableSDH(tableSDH);
1301 			UT_return_val_if_fail(sdhEndTable,false);
1302 			posEndTable = m_pDoc->getStruxPosition(sdhEndTable);
1303 			bool bKeepGoing = true;
1304 			while(bKeepGoing)
1305 			{
1306 				posCell = m_pDoc->getStruxPosition(sdhCell)+1;
1307 				getCellParams(posCell,&dLeft,&dRight,&dTop,&dBot);
1308 				dBot -= diff;
1309 				UT_sint32 row = dTop;
1310 				if(dTop != origTop)
1311 				{
1312 					dTop -= diff;
1313 				}
1314 				_changeCellTo(posTable,row,dLeft,dLeft,dRight,dTop,dBot);
1315 
1316 				bRes = m_pDoc->getNextStruxOfType(sdhCell,PTX_SectionCell,&sdhNextCell);
1317 				PT_DocPosition posNextCell = 0;
1318 				if(bRes)
1319 				{
1320 					posNextCell = m_pDoc->getStruxPosition(sdhNextCell);
1321 					if(posNextCell > posEndTable)
1322 					{
1323 						posNextCell = 0;
1324 						bKeepGoing = false;
1325 						break;
1326 					}
1327 				}
1328 				else
1329 				{
1330 					bKeepGoing = false;
1331 					break;
1332 				}
1333 				sdhCell = sdhNextCell;
1334 			}
1335 
1336 		}
1337 	}
1338 //
1339 // Look for a whole merged column
1340 //
1341 	if((dTop==0) && (dBot == numRows))
1342 	{
1343 //
1344 // Yep one whole col merged.
1345 //
1346 // Look for the number of cols spanned now
1347 //
1348 		if(dRight > (dLeft+1))
1349 		{
1350 //
1351 // Yep we have problem, we'll fix it. Subtract this number from all the cells
1352 // Right attach from this cell and left and right for all cells to the right
1353 // of it
1354 // This is a bit tricky
1355 // because we don't want to subtract the difference twice so we'll make a
1356 // vector of unique cell sdh's and only do our thing one those that aren't in
1357 // it
1358 //
1359 			UT_sint32 diff = dRight - dLeft -1;
1360 			UT_sint32 origLeft = dLeft;
1361 			UT_sint32 origRight = dRight;
1362 			pf_Frag_Strux* sdhCell = NULL;
1363 			PT_DocPosition posCell = 0;
1364 			UT_GenericVector<pf_Frag_Strux*> vecCells;
1365 			posCell = findCellPosAt(posTable, dTop, dLeft)+1;
1366 			m_pDoc->getStruxOfTypeFromPosition(posCell,PTX_SectionCell,&sdhCell);
1367 			vecCells.addItem(sdhCell);
1368 			getCellParams(posCell,&dLeft,&dRight,&dTop,&dBot);
1369 			dRight -= diff;
1370 			_changeCellTo(posTable,dTop,dLeft,dLeft,dRight,dTop,dBot);
1371 			UT_sint32 row,col=0;
1372 			for (col = 0; col < numCols; col++)
1373 			{
1374 				for(row =0; row < numRows;row++)
1375 				{
1376 					posCell = findCellPosAt(posTable, row, col)+1;
1377 					m_pDoc->getStruxOfTypeFromPosition(posCell,PTX_SectionCell,&sdhCell);
1378 					if((sdhCell==NULL) || (vecCells.findItem(sdhCell) >= 0))
1379 					{
1380 						continue;
1381 					}
1382 					getCellParams(posCell,&dLeft,&dRight,&dTop,&dBot);
1383 					bool bDoIt = false;
1384 					if(dLeft > origLeft)
1385 					{
1386 						dLeft -= diff;
1387 						bDoIt = true;
1388 					}
1389 					if(dRight >= origRight)
1390 					{
1391 						dRight -= diff;
1392 						bDoIt = true;
1393 					}
1394 					if(bDoIt)
1395 					{
1396 						vecCells.addItem(sdhCell);
1397 						_changeCellTo(posTable,row,col,dLeft,dRight,dTop,dBot);
1398 					}
1399 				}
1400 			}
1401 		}
1402 	}
1403 //
1404 // Now trigger a rebuild of the whole table by sending a changeStrux to the table strux
1405 // with the restored line-type property it has before.
1406 //
1407 	iLineType += 1;
1408 	_restoreCellParams(posTable,iLineType);
1409 	setPoint(posDestination);
1410 	_fixInsertionPointCoords();
1411 	_ensureInsertionPointOnScreen();
1412 	notifyListeners(AV_CHG_MOTION);
1413 	return true;
1414 }
1415 
1416 
1417 /*!
1418  * Move the caret to the next or previous cell in a table. If at either end
1419  * insert a new row.
1420  */
cmdAdvanceNextPrevCell(bool bGoNext)1421 bool FV_View::cmdAdvanceNextPrevCell(bool bGoNext)
1422 {
1423 	if(!isInTable())
1424 	{
1425 		return false;
1426 	}
1427 
1428 	pf_Frag_Strux* sdhCell = NULL;
1429 	pf_Frag_Strux* sdhNextPrevCell = NULL;
1430 	bool bRes = m_pDoc->getStruxOfTypeFromPosition(getPoint(),PTX_SectionCell,&sdhCell);
1431 	UT_return_val_if_fail(bRes,false);
1432 	fl_CellLayout * pCL = static_cast<fl_CellLayout *>(m_pDoc->getNthFmtHandle(sdhCell,m_pLayout->getLID()));
1433 	UT_return_val_if_fail(pCL,false);
1434 	if (bGoNext && pCL->getNext())
1435 	{
1436 		sdhNextPrevCell = pCL->getNext()->getStruxDocHandle();
1437 		UT_return_val_if_fail(sdhNextPrevCell && (sdhNextPrevCell->getPos() > sdhCell->getPos()),false);
1438 	}
1439 	else if (!bGoNext && pCL->getPrev())
1440 	{
1441 		sdhNextPrevCell = pCL->getPrev()->getStruxDocHandle();
1442 		UT_return_val_if_fail(sdhNextPrevCell && (sdhNextPrevCell->getPos() < sdhCell->getPos()),false);
1443 	}
1444 	else
1445 	{
1446 		return cmdInsertRow(getPoint(),!bGoNext);
1447 	}
1448 
1449 	setPoint(sdhNextPrevCell->getPos()+2);
1450 	_fixInsertionPointCoords();
1451 	_ensureInsertionPointOnScreen();
1452 	notifyListeners(AV_CHG_MOTION);
1453 	return true;
1454 }
1455 
1456 /*!
1457  * Convert a text fragment to a table to Text.
1458  * The column delimiters are tabs, commas and spaces as follows:
1459  * iDelim == 0 Use tabs
1460  * iDelim == 1 Use commas
1461  * iDelim == 2 Use spaces
1462  * iDelim == 3 Use tabs, commas and spaces as delemiters
1463  * Paragraph breaks are the row delimiters.
1464  */
1465 
cmdTextToTable(UT_uint32 iDelim)1466 bool FV_View::cmdTextToTable(UT_uint32 iDelim)
1467 {
1468 	STD_DOUBLE_BUFFERING_FOR_THIS_FUNCTION
1469 
1470 	UT_return_val_if_fail(!isSelectionEmpty(), false);
1471 	UT_return_val_if_fail(!isInHdrFtr(getPoint()), false);
1472 	UT_return_val_if_fail(getSelectionMode() == FV_SelectionMode_Single, false);
1473 	UT_GenericVector<fl_BlockLayout *> vecBlocks;
1474 	getBlocksInSelection(&vecBlocks, false);
1475 	UT_return_val_if_fail(vecBlocks.getItemCount() > 0, false);
1476 	fl_BlockLayout * pBL = NULL;
1477 	UT_uint32 numCols = 0;
1478 	PT_DocPosition posStart = 0;
1479 	PT_DocPosition begPos = 0;
1480 	PT_DocPosition endPos = 0;
1481 	UT_UTF8String sWords;
1482 	UT_GrowBuf * pBuf = NULL;
1483 	for (UT_sint32 k = 0; k < vecBlocks.getItemCount(); k++)
1484 	{
1485 		pBL = vecBlocks.getNthItem(k);
1486 		pBuf = new UT_GrowBuf(1024);
1487 		pBL->getBlockBuf(pBuf);
1488 		posStart = pBL->getPosition(false);
1489 		UT_uint32 count = 0;
1490 		bool bGetNext = true;
1491 		while(bGetNext)
1492 		{
1493 			bGetNext = pBL->getNextTableElement(pBuf,posStart,begPos,endPos, sWords, iDelim);
1494 			if(begPos != 0)
1495 			{
1496 				count++;
1497 				posStart = endPos+1;
1498 			}
1499 		}
1500 		delete pBuf;
1501 		numCols = UT_MAX(numCols, count);
1502 	}
1503 	UT_uint32 numRows = vecBlocks.getItemCount();
1504 	UT_return_val_if_fail(numCols > 0, false);
1505 	UT_return_val_if_fail(numRows > 0, false);
1506 
1507 	pBL = vecBlocks.getNthItem(numRows-1);
1508 	PT_DocPosition posTableStart = pBL->getPosition(true) + pBL->getLength();
1509 
1510 	// Signal PieceTable Change
1511 	_saveAndNotifyPieceTableChange();
1512 
1513 	// Turn off list updates
1514 
1515 	m_pDoc->disableListUpdates();
1516 	m_pDoc->beginUserAtomicGlob();
1517 	_clearSelection();
1518 	setPoint(posTableStart);
1519 	UT_Error e = UT_OK;
1520 //
1521 // OK let's create that table now!
1522 //
1523 //
1524 // insert a block to terminate the text before this.
1525 //
1526 	PT_DocPosition pointBreak = getPoint();
1527 	e = m_pDoc->insertStrux(getPoint(),PTX_Block);
1528 //
1529 // Insert the table strux at the same spot. This will make the table link correctly in the
1530 // middle of the broken text.
1531 //
1532 	e |= static_cast<UT_sint32>(m_pDoc->insertStrux(getPoint(),PTX_SectionTable,NULL,NULL));
1533 //
1534 // stuff for cell insertion.
1535 //
1536 	UT_uint32 i,j;
1537 	const gchar * attrs[3] = {"style","Normal",NULL};
1538 	const gchar * props[9] = {NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL};
1539 	UT_String sRowTop = "top-attach";
1540 	UT_String sRowBot = "bot-attach";
1541 	UT_String sColLeft = "left-attach";
1542 	UT_String sColRight = "right-attach";
1543 	UT_String sTop,sBot,sLeft,sRight;
1544 	for(i=0;i<numRows;i++)
1545 	{
1546 		UT_String_sprintf(sTop,"%d",i);
1547 		UT_String_sprintf(sBot,"%d",i+1);
1548 		props[0] = sRowTop.c_str();
1549 		props[1] = sTop.c_str();
1550 		props[2] = sRowBot.c_str();
1551 		props[3] = sBot.c_str();
1552 		for(j=0;j<numCols;j++)
1553 		{
1554 			UT_String_sprintf(sLeft,"%d",j);
1555 			UT_String_sprintf(sRight,"%d",j+1);
1556 			props[4] = sColLeft.c_str();
1557 			props[5] = sLeft.c_str();
1558 			props[6] = sColRight.c_str();
1559 			props[7] = sRight.c_str();
1560 			e |= static_cast<UT_sint32>(m_pDoc->insertStrux(getPoint(),PTX_SectionCell,NULL,props));
1561 			pointBreak = getPoint();
1562 			e |= static_cast<UT_sint32>(m_pDoc->insertStrux(getPoint(),PTX_Block,attrs,NULL));
1563 			UT_DEBUGMSG(("SEVIOR: 4  cur point %d \n",getPoint()));
1564 			if(getPoint() == pointBreak)
1565 			{
1566 				setPoint(pointBreak+1);
1567 			}
1568 			e |= static_cast<UT_sint32>(m_pDoc->insertStrux(getPoint(),PTX_EndCell));
1569 		}
1570 	}
1571 	e |= static_cast<UT_sint32>(m_pDoc->insertStrux(getPoint(),PTX_EndTable));
1572 //
1573 // Done! Now fill it.
1574 //
1575 	posTableStart +=3;
1576 	pf_Frag_Strux* sdhTable = NULL;
1577 	pf_Frag_Strux* sdhCell = NULL;
1578 	bool b =m_pDoc->getStruxOfTypeFromPosition(posTableStart,PTX_SectionTable,&sdhTable);
1579 	UT_return_val_if_fail(b,false);
1580 	PT_DocPosition posCell = posTableStart;
1581 	for(i =0; i< numRows;i++)
1582 	{
1583 		pBL = vecBlocks.getNthItem(i);
1584 		pBuf = new UT_GrowBuf(1024);
1585 		pBL->getBlockBuf(pBuf);
1586 		posStart = pBL->getPosition(false);
1587 		bool bEnd = false;
1588 		for( j = 0; !bEnd && j < numCols; j++)
1589 		{
1590 			sdhCell = m_pDoc->getCellSDHFromRowCol(sdhTable,isShowRevisions(),PD_MAX_REVISION,i,j);
1591 			posCell = m_pDoc->getStruxPosition(sdhCell)+1; // Points at block
1592 			sWords.clear();
1593 			bEnd = !pBL->getNextTableElement(pBuf,posStart,	begPos,	endPos,	sWords,	iDelim);
1594 			if(begPos == endPos)
1595 			{
1596 			    posStart = endPos+1;
1597 			    continue;
1598 			}
1599 			if(((j < numCols-1) && (begPos > 0)) || ((j == numCols-1) && (endPos - pBL->getPosition(false)) >= pBuf->getLength()))
1600 			{
1601 				copyToLocal(begPos, endPos);
1602 				_pasteFromLocalTo(posCell+1);
1603 				posStart = endPos+1;
1604 			}
1605 			else if((j==numCols-1) && (begPos > 0))
1606 			{
1607 				copyToLocal(begPos, endPos);
1608 				_pasteFromLocalTo(posCell+1);
1609 				posStart = endPos+1;
1610 				break;
1611 			}
1612 		}
1613 		delete pBuf;
1614 	}
1615 	pBL = vecBlocks.getNthItem(0);
1616 	begPos = pBL->getPosition();
1617 	pBL = vecBlocks.getNthItem(numRows-1);
1618 	endPos = pBL->getPosition(true) + pBL->getLength();
1619 	UT_uint32 iRealDeleteCount;
1620 
1621 	m_pDoc->deleteSpan(begPos,endPos,NULL,iRealDeleteCount);
1622 
1623 
1624 	// Signal PieceTable Changes have finished
1625 	while(m_iPieceTableState > 0)
1626 	  _restorePieceTableState();
1627 
1628 	_restorePieceTableState();
1629 	m_pDoc->clearDoingPaste();
1630 	m_pDoc->setDontImmediatelyLayout(false);
1631 
1632 	// restore updates and clean up dirty lists
1633 	m_pDoc->enableListUpdates();
1634 	m_pDoc->updateDirtyLists();
1635 
1636 	_generalUpdate();
1637 
1638 	m_pDoc->endUserAtomicGlob();
1639 
1640 
1641 	setPoint(posTableStart);
1642 	PT_DocPosition posEOD;
1643 	UT_DebugOnly<bool> bRes = getEditableBounds(true, posEOD);
1644 	UT_ASSERT(bRes);
1645 	while(!isPointLegal() && getPoint() < posEOD)
1646 	{
1647 	  setPoint(getPoint()+1);
1648 	}
1649 	while(!isPointLegal() && (getPoint() > 2))
1650 	{
1651 	  setPoint(getPoint()-1);
1652 	}
1653 	_fixInsertionPointCoords();
1654 	_ensureInsertionPointOnScreen();
1655 //
1656 // We're done!
1657 //
1658 	return true;
1659 }
1660 /*!
1661  * Make a table columns autosizing by removing all the column properties.
1662  */
cmdAutoSizeCols(void)1663 bool FV_View::cmdAutoSizeCols(void)
1664 {
1665 	STD_DOUBLE_BUFFERING_FOR_THIS_FUNCTION
1666 
1667 //
1668 // Got all we need, now set things up to do the delete nicely
1669 //
1670 	// Signal PieceTable Change
1671 	_saveAndNotifyPieceTableChange();
1672 
1673 	// Turn off list updates
1674 
1675 	m_pDoc->disableListUpdates();
1676 	m_pDoc->beginUserAtomicGlob();
1677 	const char * pszTable[3] = {NULL,NULL,NULL};
1678 	pszTable[0] = "table-column-props";
1679 	pszTable[1] = "1";
1680 	m_pDoc->changeStruxFmt(PTC_RemoveFmt,getPoint(),getPoint(),NULL,pszTable,PTX_SectionTable);
1681 	pszTable[0] = "table-column-leftpos";
1682 	m_pDoc->changeStruxFmt(PTC_RemoveFmt,getPoint(),getPoint(),NULL,pszTable,PTX_SectionTable);
1683 	m_pDoc->setDontImmediatelyLayout(false);
1684 
1685 	// Signal PieceTable Changes have finished
1686 	_restorePieceTableState();
1687 	_generalUpdate();
1688 	m_pDoc->endUserAtomicGlob();
1689 
1690 
1691 	// restore updates and clean up dirty lists
1692 	m_pDoc->enableListUpdates();
1693 	m_pDoc->updateDirtyLists();
1694 	_fixInsertionPointCoords();
1695 	_ensureInsertionPointOnScreen();
1696 	notifyListeners(AV_CHG_MOTION);
1697 	return true;
1698 }
1699 
1700 
1701 /*!
1702  * Make a table Rows autosizing by removing all the row properties.
1703  */
cmdAutoSizeRows(void)1704 bool FV_View::cmdAutoSizeRows(void)
1705 {
1706 	STD_DOUBLE_BUFFERING_FOR_THIS_FUNCTION
1707 
1708 //
1709 // Got all we need, now set things up to do the delete nicely
1710 //
1711 	// Signal PieceTable Change
1712 	_saveAndNotifyPieceTableChange();
1713 
1714 	// Turn off list updates
1715 
1716 	m_pDoc->disableListUpdates();
1717 	m_pDoc->beginUserAtomicGlob();
1718 	const char * pszTable[3] = {NULL,NULL,NULL};
1719 	pszTable[0] = "table-row-heights";
1720 	pszTable[1] = "1";
1721 	pszTable[2] = NULL;
1722 	m_pDoc->changeStruxFmt(PTC_RemoveFmt,getPoint(),getPoint(),NULL,pszTable,PTX_SectionTable);
1723 	pszTable[0] = "table-column-leftpos";
1724 	m_pDoc->changeStruxFmt(PTC_RemoveFmt,getPoint(),getPoint(),NULL,pszTable,PTX_SectionTable);
1725 	m_pDoc->setDontImmediatelyLayout(false);
1726 
1727 	// Signal PieceTable Changes have finished
1728 	_restorePieceTableState();
1729 	_generalUpdate();
1730 	m_pDoc->endUserAtomicGlob();
1731 
1732 
1733 	// restore updates and clean up dirty lists
1734 	m_pDoc->enableListUpdates();
1735 	m_pDoc->updateDirtyLists();
1736 	_fixInsertionPointCoords();
1737 	_ensureInsertionPointOnScreen();
1738 	notifyListeners(AV_CHG_MOTION);
1739 	return true;
1740 }
1741 
1742 
1743 /*!
1744  * Make a table Rows autosizing by removing all the row and col properties.
1745  */
cmdAutoFitTable(void)1746 bool FV_View::cmdAutoFitTable(void)
1747 {
1748 	STD_DOUBLE_BUFFERING_FOR_THIS_FUNCTION
1749 
1750 //
1751 // Got all we need, now set things up to do the delete nicely
1752 //
1753 	// Signal PieceTable Change
1754 	_saveAndNotifyPieceTableChange();
1755 
1756 	// Turn off list updates
1757 
1758 	m_pDoc->disableListUpdates();
1759 	m_pDoc->beginUserAtomicGlob();
1760 	const char * pszTable[7] = {NULL,NULL,NULL,NULL,NULL,NULL,NULL};
1761 	pszTable[0] = "table-row-heights";
1762 	pszTable[1] = "1";
1763 	pszTable[2] =  "table-column-leftpos";
1764 	pszTable[3] = "1";
1765 	pszTable[4] = "table-column-props";
1766 	pszTable[5] = "1";
1767 
1768 	m_pDoc->changeStruxFmt(PTC_RemoveFmt,getPoint(),getPoint(),NULL,pszTable,PTX_SectionTable);
1769 	pszTable[0] = "homogeneous";
1770 	pszTable[1] = "1";
1771 	pszTable[2] = NULL;
1772 	pszTable[3] = NULL;
1773 
1774 	m_pDoc->changeStruxFmt(PTC_AddFmt,getPoint(),getPoint(),NULL,pszTable,PTX_SectionTable);
1775 	m_pDoc->setDontImmediatelyLayout(false);
1776 
1777 	// Signal PieceTable Changes have finished
1778 	_restorePieceTableState();
1779 	_generalUpdate();
1780 	m_pDoc->endUserAtomicGlob();
1781 
1782 
1783 	// restore updates and clean up dirty lists
1784 	m_pDoc->enableListUpdates();
1785 	m_pDoc->updateDirtyLists();
1786 	_fixInsertionPointCoords();
1787 	_ensureInsertionPointOnScreen();
1788 	notifyListeners(AV_CHG_MOTION);
1789 	return true;
1790 }
1791 
1792 
1793 /*!
1794  * Insert a column containing the position posCol, insert the column before the
1795  * current column.
1796  */
cmdInsertCol(PT_DocPosition posCol,bool bBefore)1797 bool FV_View::cmdInsertCol(PT_DocPosition posCol, bool bBefore)
1798 {
1799 	STD_DOUBLE_BUFFERING_FOR_THIS_FUNCTION
1800 
1801 	UT_sint32 numColsForInsertion = getNumColumnsInSelection();
1802 	if(numColsForInsertion == 0)
1803 	{
1804 		return false;
1805 	}
1806 
1807 	pf_Frag_Strux* cellSDH,*tableSDH;
1808 	bool bRes = m_pDoc->getStruxOfTypeFromPosition(posCol,PTX_SectionCell,&cellSDH);
1809 	UT_return_val_if_fail(bRes, false);
1810 	bRes = m_pDoc->getStruxOfTypeFromPosition(posCol,PTX_SectionTable,&tableSDH);
1811 	UT_return_val_if_fail(bRes, false);
1812 	PT_DocPosition posTable = m_pDoc->getStruxPosition(tableSDH) + 1;
1813 	PT_DocPosition posCell = posCol;
1814 	UT_sint32 iLeft,iRight,iTop,iBot;
1815 	getCellParams(posCell, &iLeft, &iRight,&iTop,&iBot);
1816 
1817 	//
1818 	// Now find the number of rows and columns in this table. This is easiest to
1819 	// get from the table container
1820 	//
1821 	fl_TableLayout * pTL = static_cast<fl_TableLayout*>(m_pDoc->getNthFmtHandle(tableSDH,m_pLayout->getLID()));
1822 	UT_return_val_if_fail(pTL,false);
1823 	fp_TableContainer *pTab = static_cast <fp_TableContainer*>(pTL->getFirstContainer());
1824 	UT_return_val_if_fail(pTab,false);
1825 	bool bInsertEnd = (!bBefore && iRight == pTab->getNumCols());
1826 
1827 	// Get the attributes and properties of the block containing posCol. These attributes and properties
1828 	// will be copied in the new cells.
1829 	fl_BlockLayout * pBL = getBlockAtPosition(posCol);
1830 	const PP_AttrProp * pAP = NULL;
1831 	m_pDoc->getAttrProp(m_pDoc->getAPIFromSDH(pBL->getStruxDocHandle()), &pAP);
1832 	UT_return_val_if_fail(pAP, false);
1833 
1834 	// Signal PieceTable Change
1835 	_saveAndNotifyPieceTableChange();
1836 
1837 	// Turn off list updates
1838 
1839 	m_pDoc->disableListUpdates();
1840 	m_pDoc->beginUserAtomicGlob();
1841 	if (!isSelectionEmpty())
1842 	{
1843 		_clearSelection();
1844 	}
1845 	m_pDoc->setDontImmediatelyLayout(true);
1846 	//
1847 	// Now trigger a rebuild of the whole table by sending a changeStrux to the table strux
1848 	// with a bogus line-type property. We'll restore it later.
1849 	//
1850 	const char * pszTable[3] = {NULL,NULL,NULL};
1851 	pszTable[0] = "list-tag";
1852 	const char * szListTag = NULL;
1853 	UT_String sListTag;
1854 	UT_sint32 iListTag;
1855 	m_pDoc->getPropertyFromSDH(tableSDH,isShowRevisions(),getRevisionLevel(),pszTable[0],&szListTag);
1856 	if(szListTag == NULL || *szListTag == '\0')
1857 	{
1858 		iListTag = 0;
1859 	}
1860 	else
1861 	{
1862 		iListTag = atoi(szListTag);
1863 		iListTag -= 1;
1864 	}
1865 	UT_String_sprintf(sListTag,"%d",iListTag);
1866 	pszTable[1] = sListTag.c_str();
1867 	UT_DEBUGMSG((" Doing Table strux change of %s %s \n",pszTable[0],pszTable[1]));
1868 	m_pDoc->changeStruxFmt(PTC_AddFmt,posTable,posTable,NULL,pszTable,PTX_SectionTable);
1869 	//
1870 	// Loop trough the whole table creating new cells where necessary to add a column.
1871 	// Also shift the left and right attach of the existing cells to make place for
1872 	// the new cells.
1873 	//
1874 	fl_CellLayout* pCL = static_cast<fl_CellLayout*>(pTL->getFirstLayout());
1875 	UT_sint32 iLeftInsert = (bBefore ? iLeft:iRight);
1876 	PT_DocPosition posFirstInsert = 0;
1877 	UT_sint32 iCurLeft, iCurRight, iCurTop, iCurBot;
1878 	UT_sint32 iRow = 0;
1879 	while (pCL)
1880 	{
1881 		if (!bInsertEnd && (pCL->getLeftAttach() < iLeftInsert) && (pCL->getRightAttach() > iLeftInsert))
1882 		{
1883 			// There is a merged cell. Do not add cells
1884 			iRow += pCL->getBottomAttach() - pCL->getTopAttach();
1885 		}
1886 		else if ((!bInsertEnd && (pCL->getTopAttach() == iRow) && (pCL->getLeftAttach() >= iLeftInsert)) ||
1887 				 (bInsertEnd && (pCL->getTopAttach() == iRow + 1)))
1888 		{
1889 			// add cells before pCL
1890 			posCell = pCL->getPosition(true);
1891 			if (posFirstInsert == 0)
1892 			{
1893 				posFirstInsert = posCell + 2;
1894 			}
1895 			iCurLeft = iLeftInsert;
1896 			for (UT_sint32 k = 0; k < numColsForInsertion; k++)
1897 			{
1898 				bRes |= _insertCellAt(posCell, iCurLeft, iCurLeft + 1, iRow, iRow + 1,
1899 									  pAP->getAttributes(), pAP->getProperties());
1900 				UT_ASSERT(bRes);
1901 				posCell += 3;
1902 				iCurLeft++;
1903 			}
1904 			iRow++;  // this variable is incremented when the cells on a given row have been added.
1905 		}
1906 
1907 		if (pCL->getRightAttach() > iLeftInsert)
1908 		{
1909 			// shift left and right attach
1910 			iCurLeft = pCL->getLeftAttach();
1911 			iCurRight = pCL->getRightAttach();
1912 			iCurTop = pCL->getTopAttach();
1913 			iCurBot = pCL->getBottomAttach();
1914 			if (pCL->getLeftAttach() >= iLeftInsert)
1915 			{
1916 				iCurLeft += numColsForInsertion;
1917 			}
1918 			iCurRight += numColsForInsertion;
1919 			posCell = m_pDoc->getStruxPosition(pCL->getStruxDocHandle());
1920 			bRes |= _changeCellAttach(posCell+1, iCurLeft, iCurRight, iCurTop, iCurBot);
1921 			UT_ASSERT(bRes);
1922 		}
1923 		pCL = static_cast<fl_CellLayout*>(pCL->getNext());
1924 	}
1925 
1926 	if (bInsertEnd)
1927 	{
1928 		// Add cells at the end of the table
1929 		posCell = m_pDoc->getStruxPosition(pTL->getEndStruxDocHandle());
1930 		if (posFirstInsert == 0)
1931 		{
1932 			posFirstInsert = posCell + 2;
1933 		}
1934 		iCurLeft = iLeftInsert;
1935 		for (UT_sint32 k = 0; k < numColsForInsertion; k++)
1936 		{
1937 			bRes |= _insertCellAt(posCell, iCurLeft, iCurLeft + 1, iRow, iRow + 1,
1938 								  pAP->getAttributes(), pAP->getProperties());
1939 			UT_ASSERT(bRes);
1940 			posCell += 3;
1941 			iCurLeft++;
1942 		}
1943 		iRow++;  // this variable is incremented when the cells on a given row have been added.
1944 	}
1945 
1946 	//
1947 	// Now trigger a rebuild of the whole table by sending a changeStrux to the table strux
1948 	// with the restored line-type property it has before.
1949 	//
1950 	iListTag += 1;
1951 	UT_String_sprintf(sListTag,"%d",iListTag);
1952 	pszTable[1] = sListTag.c_str();
1953 	UT_DEBUGMSG(("SEVIOR: Doing Table strux change of %s %s \n",pszTable[0],pszTable[1]));
1954 	m_pDoc->changeStruxFmt(PTC_AddFmt,posTable,posTable,NULL,pszTable,PTX_SectionTable);
1955 	//
1956 	// OK finish everything off with the various parameters which allow the formatter to
1957 	// be updated.
1958 	//
1959 	m_pDoc->setDontImmediatelyLayout(false);
1960 
1961 	// Signal PieceTable Changes have finished
1962 	_restorePieceTableState();
1963 	_generalUpdate();
1964 	m_pDoc->endUserAtomicGlob();
1965 
1966 	// restore updates and clean up dirty lists
1967 	m_pDoc->enableListUpdates();
1968 	m_pDoc->updateDirtyLists();
1969 	// Put the insertion point in a legal position
1970 	//
1971 	setPoint(posFirstInsert);
1972 	_fixInsertionPointCoords();
1973 	_ensureInsertionPointOnScreen();
1974 	notifyListeners(AV_CHG_MOTION);
1975 	return bRes;
1976 }
1977 
1978 /*!
1979  * posRow is the position of the start of the selection in the table.
1980  * insert rows into the table.
1981  */
cmdInsertRow(PT_DocPosition posRow,bool bBefore)1982 bool FV_View::cmdInsertRow(PT_DocPosition posRow, bool bBefore)
1983 {
1984 	STD_DOUBLE_BUFFERING_FOR_THIS_FUNCTION
1985 
1986 	UT_sint32 numRowsForInsertion = getNumRowsInSelection();
1987 	if(numRowsForInsertion == 0)
1988 	{
1989 		if(isSelectionEmpty() && isInTable(posRow))
1990 		{
1991 			numRowsForInsertion = 1;
1992 		}
1993 		else
1994 		{
1995 			return false;
1996 		}
1997 	}
1998 
1999 	pf_Frag_Strux* cellSDH,*tableSDH;
2000 	bool bRes = m_pDoc->getStruxOfTypeFromPosition(posRow,PTX_SectionCell,&cellSDH);
2001 	UT_return_val_if_fail(bRes, false);
2002 	bRes = m_pDoc->getStruxOfTypeFromPosition(posRow,PTX_SectionTable,&tableSDH);
2003 	UT_return_val_if_fail(bRes, false);
2004 	PT_DocPosition posTable = m_pDoc->getStruxPosition(tableSDH) + 1;
2005 	PT_DocPosition posCell = posRow;
2006 	UT_sint32 iLeft,iRight,iTop,iBot;
2007 	getCellParams(posCell, &iLeft, &iRight,&iTop,&iBot);
2008 
2009 	//
2010 	// Now find the number of rows and columns in this table. This is easiest to
2011 	// get from the table container
2012 	//
2013 	fl_TableLayout * pTL = static_cast<fl_TableLayout*>(m_pDoc->getNthFmtHandle(tableSDH,m_pLayout->getLID()));
2014 	UT_return_val_if_fail(pTL,false);
2015 	fp_TableContainer *pTab = static_cast <fp_TableContainer*>(pTL->getFirstContainer());
2016 	UT_return_val_if_fail(pTab,false);
2017 	UT_sint32 numCols = pTab->getNumCols();
2018 	UT_sint32 numRows = pTab->getNumRows();
2019 
2020 	// Get the attributes and properties of the block containing posRow. These attributes and properties
2021 	// will be copied in the new cell.
2022 	fl_BlockLayout * pBL = getBlockAtPosition(posRow);
2023 	const PP_AttrProp * pAP = NULL;
2024 	m_pDoc->getAttrProp(m_pDoc->getAPIFromSDH(pBL->getStruxDocHandle()), &pAP);
2025 	UT_return_val_if_fail(pAP, false);
2026 
2027 	//
2028 	// Find the position in the piece table to insert the row.
2029 	// Have to handle table with merged cells. Find out if a merged cell
2030 	// interferes with the insert cmd and set bComplexInsert to true in that case.
2031 	// Then create a vector of columns where a new cell should be inserted
2032 
2033 	fl_CellLayout* pCL = NULL;
2034 	fp_CellContainer* pCell = NULL;
2035 	bool bComplexInsert = false;
2036 	UT_sint32 iTopInsert = (bBefore ? iTop:iBot);
2037 	UT_sint32 prevTop = iTopInsert;
2038 	std::vector<UT_sint32> vColInsert;
2039 	if (bBefore || (iBot < numRows))
2040 	{
2041 		pCell = pTab->getCellAtRowColumn(iTopInsert,0);
2042 		UT_return_val_if_fail(pCell,false);
2043 		UT_sint32 iPrevRight = 0;
2044 		while (pCell && pCell->getTopAttach() < iTopInsert)
2045 		{
2046 			pCell = static_cast<fp_CellContainer*>(pCell->getNext());
2047 		}
2048 		UT_return_val_if_fail(pCell,false);
2049 		pCL = static_cast<fl_CellLayout *>(pCell->getSectionLayout());
2050 		UT_return_val_if_fail(pCL,false);
2051 		posCell = pCL->getPosition(true);
2052 		while (pCell && pCell->getTopAttach() == iTopInsert)
2053 		{
2054 			if (pCell->getLeftAttach() != iPrevRight)
2055 			{
2056 				bComplexInsert = true;
2057 			}
2058 			iPrevRight = pCell->getRightAttach();
2059 			for (UT_sint32 k = pCell->getLeftAttach(); k < pCell->getRightAttach(); k++)
2060 			{
2061 				vColInsert.push_back(k);
2062 			}
2063 			pCell = static_cast<fp_CellContainer*>(pCell->getNext());
2064 		}
2065 		if (iPrevRight != numCols)
2066 		{
2067 			bComplexInsert = true;
2068 		}
2069 	}
2070 	else
2071 	{
2072 		// insert cells at the end of the table
2073 		pf_Frag_Strux* endTableSDH = pTL->getEndStruxDocHandle();
2074 		UT_return_val_if_fail(endTableSDH,false);
2075 		posCell = m_pDoc->getStruxPosition(endTableSDH);
2076 		for (UT_sint32 k = 0; k < numCols; k++)
2077 		{
2078 			vColInsert.push_back(k);
2079 		}
2080 	}
2081 
2082 	//
2083 	// Got all we need, now set things up to do the delete nicely
2084 	//
2085 
2086 	// Signal PieceTable Change
2087 	_saveAndNotifyPieceTableChange();
2088 
2089 	// Turn off list updates
2090 	m_pDoc->disableListUpdates();
2091 	m_pDoc->beginUserAtomicGlob();
2092 	if (!isSelectionEmpty())
2093 	{
2094 		_clearSelection();
2095 	}
2096 	m_pDoc->setDontImmediatelyLayout(true);
2097 
2098 	//
2099 	// Now trigger a rebuild of the whole table by sending a changeStrux to the table strux
2100 	// with a bogus line-type property. We'll restore it later.
2101 	//
2102 	const char * pszTable[3] = {NULL,NULL,NULL};
2103 	pszTable[0] = "list-tag";
2104 	const char * szListTag = NULL;
2105 	UT_String sListTag;
2106 	UT_sint32 iListTag;
2107 	m_pDoc->getPropertyFromSDH(tableSDH,isShowRevisions(),getRevisionLevel(),pszTable[0],&szListTag);
2108 	if(szListTag == NULL || *szListTag == '\0')
2109 	{
2110 		iListTag = 0;
2111 	}
2112 	else
2113 	{
2114 		iListTag = atoi(szListTag);
2115 		iListTag -= 1;
2116 	}
2117 	UT_String_sprintf(sListTag,"%d",iListTag);
2118 	pszTable[1] = sListTag.c_str();
2119 	UT_DEBUGMSG(("Sevior: Doing Table strux change of %s %s \n",pszTable[0],pszTable[1]));
2120 	m_pDoc->changeStruxFmt(PTC_AddFmt,posTable,posTable,NULL,pszTable,PTX_SectionTable);
2121 
2122 	//
2123 	// Now insert rows.
2124 	//
2125 
2126 	PT_DocPosition posInsert = posCell + 2;
2127 
2128 	UT_sint32 j = 0;
2129 	for(j=0; j< numRowsForInsertion; j++)
2130 	{
2131 		std::vector<UT_sint32>::iterator it = vColInsert.begin();
2132 		for(; it != vColInsert.end(); ++it)
2133 		{
2134 			bRes |= _insertCellAt(posCell, (*it), (*it)+1, prevTop, prevTop+1,
2135 								 pAP->getAttributes(), pAP->getProperties());
2136 			UT_ASSERT(bRes);
2137 			posCell += 3;
2138 		}
2139 		prevTop++;
2140 	}
2141 	//
2142 	// OK! starting immediately after this insert loop through the table adding 1 to top and bottom
2143 	//
2144 	UT_sint32 iCurLeft,iCurRight,iCurTop,iCurBot;
2145 	bRes = m_pDoc->getStruxOfTypeFromPosition(posCell-2,PTX_SectionCell,&cellSDH);
2146 	pCL = static_cast<fl_CellLayout*>(m_pDoc->getNthFmtHandle(cellSDH,m_pLayout->getLID()));
2147 	pCL = static_cast<fl_CellLayout*>(pCL->getNext());
2148     while(pCL)
2149 	{
2150 		iCurLeft = pCL->getLeftAttach();
2151 		iCurRight = pCL->getRightAttach();
2152 		iCurTop = pCL->getTopAttach() + numRowsForInsertion;
2153 		iCurBot = pCL->getBottomAttach() + numRowsForInsertion;
2154 		posCell = m_pDoc->getStruxPosition(pCL->getStruxDocHandle());
2155 		bRes |= _changeCellAttach(posCell+1,iCurLeft,iCurRight,iCurTop,iCurBot);
2156 		UT_ASSERT(bRes);
2157 		pCL = static_cast<fl_CellLayout*>(pCL->getNext());
2158 	}
2159 
2160 	if (bComplexInsert)
2161 	{
2162 		// We also need to modify bot-Attach of the merged cells that interfere with the inserted rows
2163 		pTab = static_cast <fp_TableContainer*>(pTL->getFirstContainer());
2164 		std::vector<UT_sint32>::iterator it = vColInsert.begin();
2165 		for (UT_sint32 k = 0; k < numCols;)
2166 		{
2167 			if (k == (*it))
2168 			{
2169 				++k;
2170 				if (it != vColInsert.end())
2171 				{
2172 					++it;
2173 				}
2174 				continue;
2175 			}
2176 			pCell = pTab->getCellAtRowColumn(iTopInsert,k);
2177 			pCL = static_cast<fl_CellLayout*>(pCell->getSectionLayout());
2178 			UT_ASSERT(pCL);
2179 			posCell = pCL->getPosition(true);
2180 			iCurLeft = pCL->getLeftAttach();
2181 			iCurRight = pCL->getRightAttach();
2182 			iCurTop = pCL->getTopAttach();
2183 			iCurBot = pCL->getBottomAttach() + numRowsForInsertion;
2184 			bRes |= _changeCellAttach(posCell+1,iCurLeft,iCurRight,iCurTop,iCurBot);
2185 			UT_ASSERT(bRes);
2186 			k = iCurRight;
2187 		}
2188 	}
2189 
2190 	//
2191 	// Now trigger a rebuild of the whole table by sending a changeStrux to the table strux
2192 	// with the restored line-type property it has before.
2193 	//
2194 	iListTag += 1;
2195 	UT_String_sprintf(sListTag,"%d",iListTag);
2196 	pszTable[1] = sListTag.c_str();
2197 	UT_DEBUGMSG(("SEVIOR: Doing Table strux change of %s %s \n",pszTable[0],pszTable[1]));
2198 	m_pDoc->changeStruxFmt(PTC_AddFmt,posTable,posTable,NULL,pszTable,PTX_SectionTable);
2199 
2200 	//
2201 	// OK finish everything off with the various parameters which allow the formatter to
2202 	// be updated.
2203 	//
2204 	setPoint(posInsert);
2205 	m_pDoc->setDontImmediatelyLayout(false);
2206 
2207 	// Signal PieceTable Changes have finished
2208 	_restorePieceTableState();
2209 	_generalUpdate();
2210 	m_pDoc->endUserAtomicGlob();
2211 
2212 	// restore updates and clean up dirty lists
2213 	m_pDoc->enableListUpdates();
2214 	m_pDoc->updateDirtyLists();
2215 	_fixInsertionPointCoords();
2216 	_ensureInsertionPointOnScreen();
2217 	notifyListeners(AV_CHG_MOTION);
2218 	return bRes;
2219 }
2220 
2221 /*!
2222  * Delete the column containing the position posCol
2223  */
cmdDeleteCol(PT_DocPosition posCol)2224 bool FV_View::cmdDeleteCol(PT_DocPosition posCol)
2225 {
2226 	STD_DOUBLE_BUFFERING_FOR_THIS_FUNCTION
2227 
2228 	pf_Frag_Strux* cellSDH,*tableSDH,*endTableSDH,*endCellSDH;
2229 	PT_DocPosition posTable,posCell2;
2230 	UT_sint32 iLeft,iRight,iTop,iBot;
2231 	getCellParams(posCol, &iLeft, &iRight,&iTop,&iBot);
2232 
2233 	bool bRes = m_pDoc->getStruxOfTypeFromPosition(posCol,PTX_SectionCell,&cellSDH);
2234 	bRes = m_pDoc->getStruxOfTypeFromPosition(posCol,PTX_SectionTable,&tableSDH);
2235 	UT_return_val_if_fail(bRes, false);
2236 
2237 	posTable = m_pDoc->getStruxPosition(tableSDH) + 1;
2238 //
2239 // Now find the number of rows and columns inthis table. This is easiest to
2240 // get from the table container
2241 //
2242 	fl_BlockLayout * pBL =	m_pLayout->findBlockAtPosition(posCol);
2243 	fp_Run * pRun;
2244 	UT_sint32 xPoint,yPoint,xPoint2,yPoint2,iPointHeight;
2245 	bool bDirection;
2246 	pRun = pBL->findPointCoords(posCol, false, xPoint,
2247 							    yPoint, xPoint2, yPoint2,
2248 							    iPointHeight, bDirection);
2249 
2250 	UT_return_val_if_fail(pRun, false);
2251 
2252 	fp_Line * pLine = pRun->getLine();
2253 	UT_return_val_if_fail(pLine, false);
2254 
2255 	fp_Container * pCon = pLine->getContainer();
2256 	UT_return_val_if_fail(pCon, false);
2257 
2258 	fp_TableContainer * pTab = static_cast<fp_TableContainer *>(pCon->getContainer());
2259 	UT_return_val_if_fail(pTab, false);
2260 
2261 	UT_sint32 numRows = pTab->getNumRows();
2262 //
2263 // If we delete the last column we're actually deleteing the table. So let's
2264 // do it.
2265 //
2266 	if(pTab->getNumCols() ==1)
2267 	{
2268 		cmdDeleteTable(posCol);
2269 		return true;
2270 	}
2271 //
2272 // Got all we need, now set things up to do the delete nicely
2273 //
2274 	// Signal PieceTable Change
2275 	_saveAndNotifyPieceTableChange();
2276 
2277 	// Turn off list updates
2278 
2279 	m_pDoc->disableListUpdates();
2280 	m_pDoc->beginUserAtomicGlob();
2281 	if (!isSelectionEmpty() && !m_FrameEdit.isActive())
2282 	{
2283 		m_pDoc->beginUserAtomicGlob();
2284 		PP_AttrProp AttrProp_Before;
2285 		_deleteSelection(&AttrProp_Before);
2286 		m_pDoc->endUserAtomicGlob();
2287 	}
2288 	else if(m_FrameEdit.isActive())
2289 	{
2290 	       m_FrameEdit.setPointInside();
2291 	}
2292 	m_pDoc->setDontImmediatelyLayout(true);
2293 //
2294 // Now trigger a rebuild of the whole table by sending a changeStrux to the table strux
2295 // with a bogus line-type property. We'll restore it later.
2296 //
2297 	const char * pszTable[3] = {NULL,NULL,NULL};
2298 	pszTable[0] = "list-tag";
2299 	const char * szListTag = NULL;
2300 	UT_String sListTag;
2301 	UT_sint32 iListTag;
2302 	m_pDoc->getPropertyFromSDH(tableSDH,isShowRevisions(),getRevisionLevel(),pszTable[0],&szListTag);
2303 	if(szListTag == NULL || *szListTag == '\0')
2304 	{
2305 		iListTag = 0;
2306 	}
2307 	else
2308 	{
2309 		iListTag = atoi(szListTag);
2310 		iListTag -= 1;
2311 	}
2312 	UT_String_sprintf(sListTag,"%d",iListTag);
2313 	pszTable[1] = sListTag.c_str();
2314 	UT_DEBUGMSG(("SEVIOR: Doing Table strux change of %s %s \n",pszTable[0],pszTable[1]));
2315 	m_pDoc->changeStruxFmt(PTC_AddFmt,posTable,posTable,NULL,pszTable,PTX_SectionTable);
2316 //
2317 // OK loop through all the rows in this column and delete the entries in the specified
2318 // column if the cell spans just the width of the column..
2319 //
2320 	UT_sint32 i =0;
2321 	for(i=0; i <numRows; i++)
2322 	{
2323 		PT_DocPosition posCell = findCellPosAt(posTable,i,iLeft);
2324 		UT_sint32 Left,Right,Top,Bot;
2325 		getCellParams(posCell+1,&Left,&Right,&Top,&Bot);
2326 		UT_DEBUGMSG(("SEVIOR: Before delete left %d right %d top %d bot %d \n",Left,Right,Top,Bot));
2327 		if((Right - Left) == 1)
2328 		{
2329 			_deleteCellAt(posTable,i, iLeft);
2330 		}
2331 	}
2332 //
2333 // OK now subtract one from all the column coordinates in the table with iLeft > iLeft
2334 // do this by running through the linked list of SectionCell fragments in the piecetable
2335 //
2336 // We stop when the position of the endCell strux is just before the position of
2337 // the endTable strux. So lets's get that now.
2338 //
2339 	bRes = m_pDoc->getNextStruxOfType(tableSDH,PTX_EndTable,&endTableSDH);
2340 	if(!bRes)
2341 	{
2342 		//
2343 		// Disaster! the table structure in the piecetable is screwed.
2344 		// we're totally stuffed now.
2345 		UT_ASSERT(UT_SHOULD_NOT_HAPPEN);
2346 	}
2347 	PT_DocPosition posEndTable = m_pDoc->getStruxPosition(endTableSDH);
2348 	PT_DocPosition posEndCell;
2349 	bool bEnd = false;
2350 	UT_sint32 iCurLeft,iCurRight,iCurTop,iCurBot,iNewLeft,iNewRight;
2351 	cellSDH = tableSDH;
2352     while(!bEnd)
2353 	{
2354 		bRes = m_pDoc->getNextStruxOfType(cellSDH,PTX_SectionCell,&cellSDH);
2355 		if(!bRes)
2356 		{
2357 			bEnd = true;
2358 			break;
2359 		}
2360 		posCell2 =  m_pDoc->getStruxPosition(cellSDH);
2361 		getCellParams(posCell2+1, &iCurLeft, &iCurRight,&iCurTop,&iCurBot);
2362 		UT_DEBUGMSG(("SEVIOR: Looking at cell left %d right %d top %d bot %d \n",iCurLeft,iCurRight,iCurTop,iCurBot));
2363 		bool bChange = false;
2364 		iNewLeft = iCurLeft;
2365 		iNewRight = iCurRight;
2366 		if(iCurLeft > iLeft)
2367 		{
2368 			bChange = true;
2369 			iNewLeft--;
2370 		}
2371 		if(iCurRight > iLeft)
2372 		{
2373 			bChange = true;
2374 			iNewRight--;
2375 		}
2376 		if(bChange)
2377 		{
2378 			UT_DEBUGMSG(("SEVIOR: changing cell to left %d right %d top %d bot %d \n",iNewLeft,iNewRight,iCurTop,iCurBot));
2379 			const char * props[9] = {NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL};
2380 			UT_String sLeft,sRight,sTop,sBot;
2381 			props[0] = "left-attach";
2382 			UT_String_sprintf(sLeft,"%d",iNewLeft);
2383 			props[1] = sLeft.c_str();
2384 			props[2] = "right-attach";
2385 			UT_String_sprintf(sRight,"%d",iNewRight);
2386 			props[3] = sRight.c_str();
2387 			props[4] = "top-attach";
2388 			UT_String_sprintf(sTop,"%d",iCurTop);
2389 			props[5] = sTop.c_str();
2390 			props[6] = "bot-attach";
2391 			UT_String_sprintf(sBot,"%d",iCurBot);
2392 			props[7] = sBot.c_str();
2393 			bRes = m_pDoc->changeStruxFmt(PTC_AddFmt,posCell2+1,posCell2+1,NULL,props,PTX_SectionCell);
2394 		}
2395 		endCellSDH = m_pDoc->getEndCellStruxFromCellSDH(cellSDH);
2396 		posEndCell =  m_pDoc->getStruxPosition(endCellSDH);
2397 		if(posEndCell+1 >= posEndTable)
2398 		{
2399 			bEnd = true;
2400 		}
2401 	}
2402 //
2403 // Now trigger a rebuild of the whole table by sending a changeStrux to the table strux
2404 // with the restored line-type property it has before.
2405 //
2406 	iListTag += 1;
2407 	UT_String_sprintf(sListTag,"%d",iListTag);
2408 	pszTable[1] = sListTag.c_str();
2409 	UT_DEBUGMSG(("SEVIOR: Doing Table strux change of %s %s \n",pszTable[0],pszTable[1]));
2410 	m_pDoc->changeStruxFmt(PTC_AddFmt,posTable,posTable,NULL,pszTable,PTX_SectionTable);
2411 //
2412 // OK finish everything off with the various parameters which allow the formatter to
2413 // be updated.
2414 //
2415 	m_pDoc->setDontImmediatelyLayout(false);
2416 
2417 	// Signal PieceTable Changes have finished
2418 	_restorePieceTableState();
2419 	_generalUpdate();
2420 	m_pDoc->endUserAtomicGlob();
2421 
2422 
2423 	// restore updates and clean up dirty lists
2424 	m_pDoc->enableListUpdates();
2425 	m_pDoc->updateDirtyLists();
2426 	_fixInsertionPointCoords();
2427 
2428 	_ensureInsertionPointOnScreen();
2429     notifyListeners(AV_CHG_MOTION);
2430 	return true;
2431 }
2432 
2433 
2434 /*!
2435  * Delete the table containing the position posRow
2436  */
cmdDeleteTable(PT_DocPosition posTable,bool bDontNotify)2437 bool FV_View::cmdDeleteTable(PT_DocPosition posTable, bool bDontNotify)
2438 {
2439 	STD_DOUBLE_BUFFERING_FOR_THIS_FUNCTION
2440 
2441 	pf_Frag_Strux* tableSDH,*endTableSDH;
2442 	PT_DocPosition posStartTable,posEndTable;
2443 	bool bRes = m_pDoc->getStruxOfTypeFromPosition(posTable,PTX_SectionTable,&tableSDH);
2444 	if(!bRes)
2445 	{
2446 		return false;
2447 	}
2448 	posStartTable = m_pDoc->getStruxPosition(tableSDH);
2449 	endTableSDH = m_pDoc->getEndTableStruxFromTableSDH(tableSDH);
2450 	posEndTable = m_pDoc->getStruxPosition(endTableSDH)+1;
2451 //
2452 // Got all we need, now set things up to do the delete nicely
2453 //
2454 	// Signal PieceTable Change
2455 	_saveAndNotifyPieceTableChange();
2456 
2457 	// Turn off list updates
2458 
2459 	m_pDoc->disableListUpdates();
2460 	m_pDoc->beginUserAtomicGlob();
2461 	if (!isSelectionEmpty())
2462 	{
2463 		_clearSelection();
2464 		_resetSelection();
2465 	}
2466 	m_pDoc->setDontImmediatelyLayout(true);
2467 //
2468 // OK do the delete
2469 //
2470 	UT_uint32 iRealDeleteCount;
2471 	//	if(m_pDoc->isFrameAtPos(posStartTable-1))
2472 	//   posStartTable--;
2473 	m_pDoc->deleteSpan( posStartTable, posEndTable, NULL,iRealDeleteCount,true);
2474 //
2475 // OK finish everything off with the various parameters which allow the formatter to
2476 // be updated.
2477 //
2478 	m_pDoc->setDontImmediatelyLayout(false);
2479 
2480 	// Signal PieceTable Changes have finished
2481 	_restorePieceTableState();
2482 	_generalUpdate();
2483 	m_pDoc->endUserAtomicGlob();
2484 
2485 	// restore updates and clean up dirty lists
2486 	m_pDoc->enableListUpdates();
2487 	m_pDoc->updateDirtyLists();
2488 	setPoint(getPoint());
2489 	//
2490 	// This method could be called from text to tablein which case
2491 	// we don't want to do this.
2492 	//
2493 	if(!bDontNotify)
2494 	{
2495 	     notifyListeners(AV_CHG_ALL);
2496 	     _fixInsertionPointCoords();
2497 	     _ensureInsertionPointOnScreen();
2498 	}
2499 	return true;
2500 }
2501 
2502 /*!
2503  * Delete the row containing the position posRow
2504  */
cmdDeleteRow(PT_DocPosition posRow)2505 bool FV_View::cmdDeleteRow(PT_DocPosition posRow)
2506 {
2507 	STD_DOUBLE_BUFFERING_FOR_THIS_FUNCTION
2508 
2509 	pf_Frag_Strux* cellSDH,*tableSDH,*endTableSDH,*endCellSDH;
2510 	PT_DocPosition posTable,posCell2;
2511 	UT_sint32 iLeft,iRight,iTop,iBot;
2512 	getCellParams(posRow, &iLeft, &iRight,&iTop,&iBot);
2513 
2514 	bool bRes = m_pDoc->getStruxOfTypeFromPosition(posRow,PTX_SectionCell,&cellSDH);
2515 	bRes = m_pDoc->getStruxOfTypeFromPosition(posRow,PTX_SectionTable,&tableSDH);
2516 	UT_return_val_if_fail(bRes, false);
2517 
2518 	posTable = m_pDoc->getStruxPosition(tableSDH) + 1;
2519 //
2520 // Now find the number of rows and columns inthis table. This is easiest to
2521 // get from the table container
2522 //
2523 	fl_TableLayout * pTabL = getTableAtPos(posRow);
2524 	if(pTabL == NULL)
2525 	{
2526 	    pTabL = getTableAtPos(posRow+1);
2527 	    if(pTabL == NULL)
2528 	    {
2529 		pTabL = getTableAtPos(posRow+2);
2530 		UT_return_val_if_fail(pTabL, false);
2531 	    }
2532 	}
2533 	fp_TableContainer * pTab = static_cast<fp_TableContainer *>(pTabL->getFirstContainer());
2534 	UT_return_val_if_fail(pTab, false);
2535 	UT_sint32 numCols = pTab->getNumCols();
2536 //
2537 // If we delete the last row we're actually deleting the table, so do that
2538 // instead.
2539 //
2540 	UT_sint32 nRows = getNumRowsInSelection();
2541 	if(pTab->getNumRows() == 1 || (nRows == pTab->getNumRows()))
2542 	{
2543 		cmdDeleteTable(posRow);
2544 		return true;
2545 	}
2546 //
2547 // Got all we need, now set things up to do the delete nicely
2548 //
2549 	// Signal PieceTable Change
2550 	_saveAndNotifyPieceTableChange();
2551 
2552 	// Turn off list updates
2553 
2554 	m_pDoc->disableListUpdates();
2555 	m_pDoc->beginUserAtomicGlob();
2556 	UT_sint32 numRows = getNumRowsInSelection();
2557 	if (!isSelectionEmpty() && !m_FrameEdit.isActive())
2558 	{
2559 		m_pDoc->beginUserAtomicGlob();
2560 		PP_AttrProp AttrProp_Before;
2561 		_deleteSelection(&AttrProp_Before);
2562 		m_pDoc->endUserAtomicGlob();
2563 	}
2564 	else if(m_FrameEdit.isActive())
2565 	{
2566 	       m_FrameEdit.setPointInside();
2567 	}
2568 	m_pDoc->setDontImmediatelyLayout(true);
2569 //
2570 // Now trigger a rebuild of the whole table by sending a changeStrux to the table strux
2571 // with a bogus line-type property. We'll restore it later.
2572 //
2573 	const char * pszTable[3] = {NULL,NULL,NULL};
2574 	pszTable[0] = "list-tag";
2575 	const char * szListTag = NULL;
2576 	UT_String sListTag;
2577 	UT_sint32 iListTag;
2578 	m_pDoc->getPropertyFromSDH(tableSDH,isShowRevisions(),getRevisionLevel(),pszTable[0],&szListTag);
2579 	if(szListTag == NULL || *szListTag == '\0')
2580 	{
2581 		iListTag = 0;
2582 	}
2583 	else
2584 	{
2585 		iListTag = atoi(szListTag);
2586 		iListTag -= 1;
2587 	}
2588 	UT_String_sprintf(sListTag,"%d",iListTag);
2589 	pszTable[1] = sListTag.c_str();
2590 	UT_DEBUGMSG(("SEVIOR: Doing Table strux change of %s %s \n",pszTable[0],pszTable[1]));
2591 	m_pDoc->changeStruxFmt(PTC_AddFmt,posTable,posTable,NULL,pszTable,PTX_SectionTable);
2592 //
2593 // OK loop through all the rows in this column and delete the entries in the specified
2594 // column if the cell spans just the width of the column..
2595 //
2596 	UT_sint32 i =0;
2597 	UT_sint32 j = 0;
2598 	for(j=numRows-1; j>=0; j--)
2599 	{
2600 		for(i=numCols-1; i >=0; i--)
2601 		{
2602 			PT_DocPosition posCell = findCellPosAt(posTable,iTop+j,i);
2603 			UT_sint32 Left,Right,Top,Bot;
2604 			getCellParams(posCell+1,&Left,&Right,&Top,&Bot);
2605 			UT_DEBUGMSG(("SEVIOR: Before delete left %d right %d top %d bot %d \n",Left,Right,Top,Bot));
2606 			if((Bot - Top) == 1)
2607 			{
2608 				_deleteCellAt(posTable,iTop+j, i);
2609 			}
2610 		}
2611 	}
2612 //
2613 // OK now subtract numRows from all the row coordinates in the table with iTop,iBot > iTop
2614 // do this by running through the linked list of SectionCell fragments in the piecetable
2615 //
2616 // We stop when the position of the endCell strux is just before the position of
2617 // the endTable strux. So lets's get that now.
2618 //
2619 	endTableSDH = m_pDoc->getEndTableStruxFromTableSDH(tableSDH);
2620 	if(!bRes || (endTableSDH == NULL))
2621 	{
2622 		//
2623 		// Disaster! the table structure in the piecetable is screwed.
2624 		// we're totally stuffed now.
2625 		UT_ASSERT(UT_SHOULD_NOT_HAPPEN);
2626 		m_pDoc->setDontImmediatelyLayout(false);
2627 
2628 		// Signal PieceTable Changes have finished
2629 		_restorePieceTableState();
2630 		m_pDoc->endUserAtomicGlob();
2631 		return false;
2632 	}
2633 	PT_DocPosition posEndTable = m_pDoc->getStruxPosition(endTableSDH);
2634 	PT_DocPosition posEndCell;
2635 	bool bEnd = false;
2636 	UT_sint32 iCurLeft,iCurRight,iCurTop,iCurBot,iNewTop,iNewBot;
2637 	cellSDH = tableSDH;
2638     while(!bEnd)
2639 	{
2640 		bRes = m_pDoc->getNextStruxOfType(cellSDH,PTX_SectionCell,&cellSDH);
2641 		if(!bRes)
2642 		{
2643 			bEnd = true;
2644 			break;
2645 		}
2646 		posCell2 =  m_pDoc->getStruxPosition(cellSDH);
2647 		getCellParams(posCell2+1, &iCurLeft, &iCurRight,&iCurTop,&iCurBot);
2648 		UT_DEBUGMSG(("SEVIOR: Looking at cell left %d right %d top %d bot %d \n",iCurLeft,iCurRight,iCurTop,iCurBot));
2649 		bool bChange = false;
2650 		iNewTop = iCurTop;
2651 		iNewBot = iCurBot;
2652 		if(iCurTop > iTop)
2653 		{
2654 			bChange = true;
2655 			iNewTop -= numRows;
2656 		}
2657 		if(iCurBot > iTop)
2658 		{
2659 			bChange = true;
2660 			iNewBot -= numRows;
2661 		}
2662 		if(bChange)
2663 		{
2664 			UT_DEBUGMSG(("SEVIOR: changing cell to left %d right %d top %d bot %d \n",iCurLeft,iCurRight,iNewTop,iNewBot));
2665 			const char * props[9] = {NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL};
2666 			UT_String sLeft,sRight,sTop,sBot;
2667 			props[0] = "left-attach";
2668 			UT_String_sprintf(sLeft,"%d",iCurLeft);
2669 			props[1] = sLeft.c_str();
2670 			props[2] = "right-attach";
2671 			UT_String_sprintf(sRight,"%d",iCurRight);
2672 			props[3] = sRight.c_str();
2673 			props[4] = "top-attach";
2674 			UT_String_sprintf(sTop,"%d",iNewTop);
2675 			props[5] = sTop.c_str();
2676 			props[6] = "bot-attach";
2677 			UT_String_sprintf(sBot,"%d",iNewBot);
2678 			props[7] = sBot.c_str();
2679 			bRes = m_pDoc->changeStruxFmt(PTC_AddFmt,posCell2+1,posCell2+1,NULL,props,PTX_SectionCell);
2680 		}
2681 		endCellSDH = m_pDoc->getEndCellStruxFromCellSDH(cellSDH);
2682 		posEndCell =  m_pDoc->getStruxPosition(endCellSDH);
2683 		if(posEndCell+1 >= posEndTable)
2684 		{
2685 			bEnd = true;
2686 		}
2687 	}
2688 //
2689 // Now trigger a rebuild of the whole table by sending a changeStrux to the table strux
2690 // with the restored line-type property it has before.
2691 //
2692 	iListTag += 1;
2693 	UT_String_sprintf(sListTag,"%d",iListTag);
2694 	pszTable[1] = sListTag.c_str();
2695 	UT_DEBUGMSG(("SEVIOR: Doing Table strux change of %s %s \n",pszTable[0],pszTable[1]));
2696 	m_pDoc->changeStruxFmt(PTC_AddFmt,posTable,posTable,NULL,pszTable,PTX_SectionTable);
2697 //
2698 // OK finish everything off with the various parameters which allow the formatter to
2699 // be updated.
2700 //
2701 	m_pDoc->setDontImmediatelyLayout(false);
2702 
2703 	// Signal PieceTable Changes have finished
2704 	_restorePieceTableState();
2705 	_generalUpdate();
2706 	m_pDoc->endUserAtomicGlob();
2707 
2708 
2709 	// restore updates and clean up dirty lists
2710 	m_pDoc->enableListUpdates();
2711 	m_pDoc->updateDirtyLists();
2712 	_fixInsertionPointCoords();
2713 
2714 	_ensureInsertionPointOnScreen();
2715     notifyListeners(AV_CHG_MOTION);
2716 	return true;
2717 }
2718 
2719 
2720 /*!
2721  * Delete the cell at the specified position
2722  */
cmdDeleteCell(PT_DocPosition)2723 bool FV_View::cmdDeleteCell(PT_DocPosition /*cellPos*/ )
2724 {
2725 #if 1
2726   UT_ASSERT(UT_NOT_IMPLEMENTED);
2727   return true ;
2728 #else
2729 	pf_Frag_Strux* cellSDH;
2730 	const char * pszLeftAttach =NULL;
2731 	const char * pszTopAttach = NULL;
2732 	UT_sint32 iLeft =-999;
2733 	UT_sint32 iTop = -999;
2734 	bool bRes = m_pDoc->getStruxOfTypeFromPosition(cellPos,PTX_SectionCell,&cellSDH);
2735 	if(!bRes)
2736 	{
2737 		return false;
2738 	}
2739 	m_pDoc->getPropertyFromSDH(cellSDH,"left-attach",&pszLeftAttach);
2740 	m_pDoc->getPropertyFromSDH(cellSDH,"top-attach",&pszTopAttach);
2741 	if(pszLeftAttach && *pszLeftAttach)
2742 	{
2743 		iLeft = atoi(pszLeftAttach);
2744 	}
2745 	if(pszTopAttach && *pszTopAttach)
2746 	{
2747 		iTop = atoi(pszTopAttach);
2748 	}
2749 //
2750 // Got all we need, now set things up to do the delete nicely
2751 //
2752 	// Signal PieceTable Change
2753 	_saveAndNotifyPieceTableChange();
2754 
2755 	// Turn off list updates
2756 
2757 	m_pDoc->disableListUpdates();
2758 	m_pDoc->beginUserAtomicGlob();
2759 	if (!isSelectionEmpty() && !m_FrameEdit.isActive())
2760 	{
2761 		m_pDoc->beginUserAtomicGlob();
2762 		PP_AttrProp AttrProp_Before;
2763 		_deleteSelection(&AttrProp_Before);
2764 		m_pDoc->endUserAtomicGlob();
2765 	}
2766 	else if(m_FrameEdit.isActive())
2767 	{
2768 	       m_FrameEdit.setPointInside();
2769 	}
2770 	m_pDoc->setDontImmediatelyLayout(true);
2771 //
2772 // delete the cell.
2773 //
2774 	_deleteCellAt(cellPos,iTop, iLeft);
2775 //
2776 // OK do all the piecetable finished changing business
2777 //
2778 	m_pDoc->setDontImmediatelyLayout(false);
2779 
2780 	// Signal PieceTable Changes have finished
2781 	_restorePieceTableState();
2782 	_generalUpdate();
2783 	m_pDoc->endUserAtomicGlob();
2784 
2785 
2786 	// restore updates and clean up dirty lists
2787 	m_pDoc->enableListUpdates();
2788 	m_pDoc->updateDirtyLists();
2789 	_fixInsertionPointCoords();
2790 
2791 	_ensureInsertionPointOnScreen();
2792     notifyListeners(AV_CHG_MOTION);
2793 	return true;
2794 #endif
2795 }
2796 
2797 
2798 /*!
2799  * Insert a table of the  number of rows and columns given.
2800  */
cmdInsertTable(UT_sint32 numRows,UT_sint32 numCols,const gchar * pPropsArray[])2801 UT_Error FV_View::cmdInsertTable(UT_sint32 numRows, UT_sint32 numCols, const gchar * pPropsArray[])
2802 {
2803 	STD_DOUBLE_BUFFERING_FOR_THIS_FUNCTION
2804 
2805 	// TODO -- why does this function return UT_Error? If bool is
2806 	// sufficient, it should return bool, and if not, than the
2807 	// UT_Error & bool operations below are probably not safe
2808 	UT_Error e = UT_OK;
2809 	if(numRows == 0 || numCols==0)
2810 	{
2811 		return 0;
2812 	}
2813 	if(isInTable(getPoint()-1) && isInTable() && isHdrFtrEdit())
2814 	{
2815 		return 0;
2816 	}
2817 	if(isInTable(getPoint()) && !isSelectionEmpty() && isHdrFtrEdit())
2818 	{
2819 		return 0;
2820 	}
2821 #if BENCHLAYOUT
2822 	printf("Doing Insert Table \n");
2823 	timespec t1;
2824 	clock_gettime(CLOCK_REALTIME, &t1);
2825 #endif
2826 
2827 
2828 //
2829 // Do all the stuff we need to make this go smoothly and to undo in a single step.
2830 //
2831 	// Signal PieceTable Changes
2832 	_saveAndNotifyPieceTableChange();
2833 
2834 	// Turn off list updates
2835 
2836 	m_pDoc->disableListUpdates();
2837 	m_pDoc->beginUserAtomicGlob();
2838 	if (!isSelectionEmpty() && !m_FrameEdit.isActive())
2839 	{
2840 		m_pDoc->setDontImmediatelyLayout(true);
2841 		m_pDoc->beginUserAtomicGlob();
2842 		PP_AttrProp AttrProp_Before;
2843 		_deleteSelection(&AttrProp_Before);
2844 		m_pDoc->endUserAtomicGlob();
2845 	}
2846 	else if(m_FrameEdit.isActive())
2847 	{
2848 	       m_FrameEdit.setPointInside();
2849 	}
2850 	else
2851 	{
2852 		m_pDoc->setDontImmediatelyLayout(true);
2853 	}
2854 	if(getHyperLinkRun(getPoint()) != NULL)
2855 	{
2856 
2857 	// Signal PieceTable Changes have finished
2858 	// restore updates and clean up dirty lists
2859 		m_pDoc->enableListUpdates();
2860 		m_pDoc->updateDirtyLists();
2861 		_restorePieceTableState();
2862 		return 0;
2863 	}
2864 //
2865 // Handle corner case of point at endTOC
2866 //
2867 	if(m_pDoc->isTOCAtPos(getPoint()-1))
2868 	{
2869 	 		setPoint(getPoint()-1);
2870 	}
2871 //
2872 // insert a block to terminate the text before this.
2873 //
2874 	PT_DocPosition pointBreak = getPoint();
2875 	PT_DocPosition pointTable = 0;
2876 	//
2877 	// Don't do this if there is a block at pointBreak already.
2878 	//
2879 	bool bInsert = false;
2880 	if((!m_pDoc->isBlockAtPos(getPoint()) && !m_pDoc->isTableAtPos(getPoint()) && !(m_pDoc->isEndFrameAtPos(getPoint()) && m_pDoc->isBlockAtPos(getPoint()-1) )) || m_pDoc->isTOCAtPos(getPoint()-2) )
2881 	{
2882 	         e = m_pDoc->insertStrux(getPoint(),PTX_Block);
2883 		 bInsert = true;
2884 	}
2885 	bool bPointBreak = false;
2886 	if(!bInsert && !m_pDoc->isTableAtPos(getPoint()) && !m_pDoc->isEndFootnoteAtPos(getPoint()-2) && !m_pDoc->isEndFootnoteAtPos(getPoint()-1) && !m_pDoc->isBlockAtPos(getPoint()))
2887 	{
2888 	         pointBreak--;
2889 		 bPointBreak = true;
2890 	}
2891 	if(!bPointBreak && m_pDoc->isBlockAtPos(getPoint()))
2892 	{
2893 	         PT_DocPosition posEnd = 0;
2894 		 getEditableBounds(true,posEnd);
2895 		 if(posEnd == getPoint())
2896 		 {
2897 		         pointBreak--;
2898 			 bPointBreak = true;
2899 		 }
2900 		 else if(m_pDoc->isSectionAtPos(getPoint()-1) || m_pDoc->isEndTableAtPos(getPoint()-1) || m_pDoc->isEndFrameAtPos(getPoint() - 1))
2901 		 {
2902 		         pointBreak--;
2903 			 bPointBreak = true;
2904 		 }
2905 		 else if(m_pDoc->isSectionAtPos(getPoint()-2))
2906 		 {
2907 		         pointBreak--;
2908 			 bPointBreak = true;
2909 		 }
2910 		 if(m_pDoc->isEndFootnoteAtPos(pointBreak))
2911 		 {
2912 		         pointBreak++;
2913 			 bPointBreak = false;
2914 		 }
2915 		 if(bPointBreak && !m_pDoc->isBlockAtPos(pointBreak))
2916 		 {
2917 		         pointBreak++;
2918 			 bPointBreak = false;
2919 		 }
2920 
2921 	}
2922 //
2923 // Insert the table strux at the same spot. This will make the table link correctly in the
2924 // middle of the broken text.
2925 //
2926 // Handle special case of not putting a table immediately after a section break
2927 //
2928 	pf_Frag_Strux* secSDH = NULL;
2929 	UT_DebugOnly<bool> bres = m_pDoc->getStruxOfTypeFromPosition(pointBreak-1,PTX_Section,&secSDH);
2930 #if DEBUG
2931 	UT_ASSERT(bres);
2932 	PT_DocPosition secPos2 = m_pDoc->getStruxPosition(secSDH);
2933 	UT_DEBUGMSG(("SEVIOR: SecPos %d pointBreak %d \n",secPos2,pointBreak));
2934 #endif
2935 	secSDH = NULL;
2936 	bres = m_pDoc->getStruxOfTypeFromPosition(pointBreak,PTX_SectionCell,&secSDH);
2937 #if DEBUG
2938 	if(secSDH != NULL)
2939 	{
2940 		PT_DocPosition secPos = m_pDoc->getStruxPosition(secSDH);
2941 		UT_DEBUGMSG(("SEVIOR: Cell Pos %d pointBreak %d \n",secPos,pointBreak));
2942 	}
2943 #endif
2944 //
2945 // Handle special case of not putting a table immediately after an end text box
2946 //
2947 	if(m_pDoc->isEndFrameAtPos(pointBreak-1))
2948 	{
2949 		pointBreak--;
2950 	}
2951 	//
2952 	// Handle special case of not putting a table in a TOC
2953 	//
2954 	if(m_pDoc->isTOCAtPos(pointBreak-1))
2955 	{
2956 		pointBreak++;
2957 	}
2958 
2959 	setPoint(pointBreak);
2960 	// Get the current attributes and properties. The user likely does not want the block properties as
2961 	// the margins and indents might not be right for a much narrower container (the cell).
2962 	// This is a ugly hack. We will only copy 2 fonts properties, font-family and font-size.
2963 	const gchar ** props_in = NULL;
2964 	const gchar * attrsBlock[3] = {"style","Normal",NULL};
2965 	const gchar * propsBlock[5] = {NULL,NULL,NULL,NULL,NULL};
2966 	const gchar * propFamily = "font-family";
2967 	const gchar * propSize = "font-size";
2968 	const gchar * szFamily = NULL;
2969 	const gchar * szSize = NULL;
2970 	const gchar * szNormalFamily = NULL;
2971 	const gchar * szNormalSize = NULL;
2972 	getCharFormat(&props_in);
2973 	if (props_in && props_in[0])
2974 	{
2975 		szFamily = UT_getAttribute(propFamily, props_in);
2976 		szSize = UT_getAttribute(propSize, props_in);
2977 	}
2978 	m_pDoc->getStyleProperty(attrsBlock[1],propFamily,szNormalFamily);
2979 	m_pDoc->getStyleProperty(attrsBlock[1],propSize,szNormalSize);
2980 	bool bFamily = (szFamily && (!szNormalFamily || (strcmp(szNormalFamily,szFamily) != 0)));
2981 	bool bSize = (szSize && (!szNormalSize || (strcmp(szNormalSize,szSize) != 0)));
2982 	if (bFamily && bSize)
2983 	{
2984 		propsBlock[0] = propFamily;
2985 		propsBlock[1] = szFamily;
2986 		propsBlock[2] = propSize;
2987 		propsBlock[3] = szSize;
2988 	}
2989 	else if (bFamily)
2990 	{
2991 		propsBlock[0] = propFamily;
2992 		propsBlock[1] = szFamily;
2993 	}
2994 	else if (bSize)
2995 	{
2996 		propsBlock[0] = propSize;
2997 		propsBlock[1] = szSize;
2998 	}
2999 
3000 	e |= static_cast<UT_sint32>(m_pDoc->insertStrux(getPoint(),PTX_SectionTable,NULL,pPropsArray));
3001 //
3002 // stuff for cell insertion.
3003 //
3004 	UT_sint32 i,j;
3005 	const gchar * props[9] = {NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL};
3006 	UT_String sRowTop = "top-attach";
3007 	UT_String sRowBot = "bot-attach";
3008 	UT_String sColLeft = "left-attach";
3009 	UT_String sColRight = "right-attach";
3010 	UT_String sTop,sBot,sLeft,sRight;
3011 	for(i=0;i<numRows;i++)
3012 	{
3013 		UT_String_sprintf(sTop,"%d",i);
3014 		UT_String_sprintf(sBot,"%d",i+1);
3015 		props[0] = sRowTop.c_str();
3016 		props[1] = sTop.c_str();
3017 		props[2] = sRowBot.c_str();
3018 		props[3] = sBot.c_str();
3019 		for(j=0;j<numCols;j++)
3020 		{
3021 			UT_String_sprintf(sLeft,"%d",j);
3022 			UT_String_sprintf(sRight,"%d",j+1);
3023 			props[4] = sColLeft.c_str();
3024 			props[5] = sLeft.c_str();
3025 			props[6] = sColRight.c_str();
3026 			props[7] = sRight.c_str();
3027 			e |= static_cast<UT_sint32>(m_pDoc->insertStrux(getPoint(),PTX_SectionCell,NULL,props));
3028 			pointBreak = getPoint();
3029 			e |= static_cast<UT_sint32>(m_pDoc->insertStrux(getPoint(),PTX_Block,attrsBlock,propsBlock));
3030 			UT_DEBUGMSG(("SEVIOR: 4  cur point %d \n",getPoint()));
3031 			if(getPoint() == pointBreak)
3032 			{
3033 				setPoint(pointBreak+1);
3034 			}
3035 			if(i == 0 && j==0)
3036 			{
3037 				pointTable = getPoint();
3038 			}
3039 			e |= static_cast<UT_sint32>(m_pDoc->insertStrux(getPoint(),PTX_EndCell));
3040 		}
3041 	}
3042 	m_pDoc->setDontImmediatelyLayout(false);
3043 
3044 #if BENCHLAYOUT
3045 	timespec t2;
3046 	clock_gettime(CLOCK_REALTIME, &t2);
3047 	double millidiff = (t2.tv_sec-t1.tv_sec)*1e3 + (t2.tv_nsec-t1.tv_nsec)/1e6;
3048 	printf("Insert TIME: %lf milliseconds\n", millidiff);
3049 #endif
3050 	e |= static_cast<UT_sint32>(m_pDoc->insertStrux(getPoint(),PTX_EndTable));
3051 
3052 	// restore updates and clean up dirty lists
3053 	m_pDoc->enableListUpdates();
3054 	m_pDoc->updateDirtyLists();
3055 
3056 	// Signal PieceTable Changes have finished
3057 	_restorePieceTableState();
3058 	_generalUpdate();
3059 
3060 	m_pDoc->endUserAtomicGlob();
3061 	setPoint(pointTable);
3062 	_makePointLegal();
3063 	_fixInsertionPointCoords();
3064 	focusChange(AV_FOCUS_HERE);
3065 	_fixInsertionPointCoords();
3066 	_ensureInsertionPointOnScreen();
3067 	AV_View::notifyListeners (AV_CHG_ALL);
3068 	return e;
3069 }
3070 
3071 bool
cmdCharInsert(const std::string & s,bool bForce)3072 FV_View::cmdCharInsert(const std::string& s, bool bForce)
3073 {
3074 	UT_UCS4String t( s );
3075 	return cmdCharInsert( t.ucs4_str(), t.length(), bForce );
3076 }
3077 
3078 
cmdCharInsert(const UT_UCSChar * text,UT_uint32 count,bool bForce)3079 bool FV_View::cmdCharInsert(const UT_UCSChar * text, UT_uint32 count, bool bForce)
3080 {
3081 	STD_DOUBLE_BUFFERING_FOR_THIS_FUNCTION
3082 
3083 	//
3084 	// Look if we should insert a pargraph before the table
3085 	//
3086 	if(m_bInsertAtTablePending && (count==1) && (text[0] != UCS_FF) && (text[0] != UCS_VTAB))
3087 	{
3088 		m_pDoc->beginUserAtomicGlob();
3089 
3090 		// Prevent access to Piecetable for things like spellchecks until
3091 		// paragraphs have stablized
3092 		//
3093 		_saveAndNotifyPieceTableChange();
3094 		m_pDoc->disableListUpdates();
3095 		PT_DocPosition pos = m_iPosAtTable;
3096 		m_pDoc->insertStrux( m_iPosAtTable,PTX_Block);
3097 		m_bInsertAtTablePending = false;
3098 
3099 		// Signal piceTable is stable again
3100 		_restorePieceTableState();
3101 
3102 		// Signal piceTable is stable again
3103 		// Signal PieceTable Changes have finished
3104 		_generalUpdate();
3105 		// restore updates and clean up dirty lists
3106 		m_pDoc->enableListUpdates();
3107 		m_pDoc->updateDirtyLists();
3108 		setPoint(pos+1);
3109 		m_iPosAtTable = 0;
3110 		_generalUpdate();
3111 		bool res = _charInsert(text, count, bForce);
3112 		m_pDoc->endUserAtomicGlob();
3113 		return res;
3114 	}
3115 
3116 	// the code below inserts a direction marker before a space if the automatic insertion of such
3117 	// markers is indicated by user's preferences and if the current keyboard language direction is
3118 	// inconsistent with the dominant direction of the paragraph (this makes phone numbers and similar
3119 	// to work in rtl languages more intuitively)
3120 
3121 	// we only do this for space ... (certain other chars can be handled in ap_EditMethods.cpp
3122 	// because they do not need knowledge of block direction)
3123 	fl_BlockLayout * pBlock = NULL;
3124 	if(count == 1 && text[0] == UCS_SPACE)
3125 	{
3126 		bool bLang = false, bMarker = false;
3127 
3128 		XAP_App::getApp()->getPrefsValueBool(static_cast<const gchar *>(XAP_PREF_KEY_ChangeLanguageWithKeyboard),
3129 											 &bLang);
3130 
3131 		const UT_LangRecord * pLR = NULL;
3132 
3133 		if(bLang)
3134 		{
3135 			pLR = XAP_App::getApp()->getKbdLanguage();
3136 
3137 			XAP_App::getApp()->getPrefsValueBool(static_cast<const gchar *>(XAP_PREF_KEY_DirMarkerAfterClosingParenthesis), &bMarker);
3138 		}
3139 
3140 		if(bMarker && pLR)
3141 		{
3142 			pBlock = m_pLayout->findBlockAtPosition(getPoint());
3143 
3144 			if(!pBlock)
3145 				goto normal_insert;
3146 
3147 			{
3148 				UT_BidiCharType iDomDir = pBlock->getDominantDirection();
3149 
3150 				UT_UCS4Char data[2];
3151 				data[1] = *text;
3152 
3153 				if(pLR->m_eDir == UTLANG_RTL && iDomDir != UT_BIDI_RTL)
3154 				{
3155 					data[0] = UCS_RLM;
3156 				}
3157 				else if(pLR->m_eDir == UTLANG_LTR  && iDomDir != UT_BIDI_LTR)
3158 				{
3159 					data[0] = UCS_LRM;
3160 				}
3161 				else
3162 				{
3163 					goto normal_insert;
3164 				}
3165 
3166 				return _charInsert(&data[0],2,bForce);
3167 			}
3168 		}
3169 	}
3170 	else if(count == 1 && text[0] == UCS_FF)
3171 	{
3172 		m_pDoc->beginUserAtomicGlob();
3173 		bool b = _charInsert(text, count, bForce);
3174 		if(b)
3175 		{
3176 			insertParagraphBreak();
3177 		}
3178 		m_pDoc->endUserAtomicGlob();
3179 		return b;
3180 	}
3181 	else if(count == 1 && text[0] == UCS_VTAB)
3182 	{
3183 		m_pDoc->beginUserAtomicGlob();
3184 		bool b = _charInsert(text, count, bForce);
3185 		if(b)
3186 		{
3187 			insertParagraphBreak();
3188 		}
3189 		m_pDoc->endUserAtomicGlob();
3190 		return b;
3191 	}
3192 
3193 normal_insert:
3194 	return _charInsert(text, count, bForce);
3195 }
3196 
cmdStartList(const gchar * style)3197 bool FV_View::cmdStartList(const gchar * style)
3198 {
3199 	m_pDoc->beginUserAtomicGlob();
3200 	fl_BlockLayout * pBlock = getCurrentBlock();
3201 	pBlock->StartList( style);
3202 	m_pDoc->endUserAtomicGlob();
3203 
3204 	return true;
3205 }
3206 
3207 
cmdStopList(void)3208 bool FV_View::cmdStopList(void)
3209 {
3210 
3211 
3212 	// Signal PieceTable Change
3213 	_saveAndNotifyPieceTableChange();
3214 
3215 	m_pDoc->beginUserAtomicGlob();
3216 	fl_BlockLayout * pBlock = getCurrentBlock();
3217 	m_pDoc->StopList(pBlock->getStruxDocHandle());
3218 	m_pDoc->endUserAtomicGlob();
3219 
3220 	// Signal PieceTable Changes have finished
3221 	_restorePieceTableState();
3222 	return true;
3223 }
3224 
3225 
cmdCharDelete(bool bForward,UT_uint32 count)3226 void FV_View::cmdCharDelete(bool bForward, UT_uint32 count)
3227 {
3228 	STD_DOUBLE_BUFFERING_FOR_THIS_FUNCTION
3229 
3230 	const gchar * properties[] = { "font-family", NULL, 0};
3231 	const gchar ** props_in = NULL;
3232 	const gchar * currentfont;
3233 	bool bisList = false;
3234 	fl_BlockLayout * curBlock = NULL;
3235 	fl_BlockLayout * nBlock = NULL;
3236 	UT_uint32 iRealDeleteCount = 0;
3237 	bool bSimple = false;
3238 
3239 	if (!isSelectionEmpty() && !m_FrameEdit.isActive())
3240 	{
3241 
3242 		// Signal PieceTable Change
3243 		_saveAndNotifyPieceTableChange();
3244 		m_pDoc->disableListUpdates();
3245 
3246 		_deleteSelection();
3247 
3248 		_generalUpdate();
3249 
3250 		// restore updates and clean up dirty lists
3251 		m_pDoc->enableListUpdates();
3252 		m_pDoc->updateDirtyLists();
3253 		_fixInsertionPointCoords();
3254 		_ensureInsertionPointOnScreen();
3255 	}
3256 	else if(m_FrameEdit.isActive())
3257     {
3258 	  deleteFrame();
3259 	}
3260 	else
3261 	{
3262 		bool b_editStarted = false;
3263 		bool b_delBlockWithFrames = false;
3264 		//
3265 		// Look to see if there is a tab - list label deal with these together
3266 		//
3267 		if((bForward == false) && (count == 1))
3268 		{
3269 		    UT_sint32 myCount= 0;
3270 			if(isTabListBehindPoint(myCount) == true)
3271 			{
3272 				curBlock = _findBlockAtPosition(getPoint());
3273 				nBlock = _findBlockAtPosition(getPoint()-myCount);
3274 				if(nBlock == curBlock)
3275 				{
3276 					count = myCount;
3277 					bisList = true;
3278 				}
3279 			}
3280 		}
3281 		if((bForward == true) && (count == 1))
3282 		{
3283 			if(isTabListAheadPoint() == true)
3284 			{
3285 //
3286 // Check we're at the start of a block
3287 //
3288 				if(getPoint() == getCurrentBlock()->getPosition())
3289 				{
3290 					bisList = true;
3291 					count = 2;
3292 				}
3293 			}
3294 		}
3295 //
3296 // Move frames to a good position in the piece table when deleting a block (joining two paragraphs
3297 // together). Also keep frame at the same position with respect to the top of the first block.
3298 //
3299 //
3300 		fl_BlockLayout * pFirstBlock = NULL;
3301 		fl_BlockLayout * pSecondBlock = NULL;
3302 
3303 		if((bForward == false) && (count == 1))
3304 		{
3305 			fl_BlockLayout * pBlock = getCurrentBlock();
3306 			if (pBlock && getPoint() == pBlock->getPosition())
3307 			{
3308 				fl_ContainerLayout * pPrevCL = pBlock->getPrev();
3309 				while (pPrevCL && pPrevCL->getContainerType() == FL_CONTAINER_FRAME)
3310 				{
3311 					pPrevCL = pPrevCL->getPrev();
3312 				}
3313 				if (pPrevCL && pPrevCL->getContainerType() == FL_CONTAINER_BLOCK)
3314 				{
3315 					pFirstBlock = static_cast <fl_BlockLayout *> (pPrevCL);
3316 					pSecondBlock = pBlock;
3317 					if ((pFirstBlock->getNumFrames() > 0) || (pSecondBlock->getNumFrames() > 0))
3318 					{
3319 						b_delBlockWithFrames = true;
3320 					}
3321 				}
3322 			}
3323 		}
3324 		else if((bForward == true) && (count == 1))
3325 		{
3326 			fl_BlockLayout * pBlock = getCurrentBlock();
3327 			if (pBlock && (getPoint() == (pBlock->getPosition()+pBlock->getLength()-1)))
3328 			{
3329 				fl_ContainerLayout * pNextCL = pBlock->getNext();
3330 				while (pNextCL && pNextCL->getContainerType() == FL_CONTAINER_FRAME)
3331 				{
3332 					pNextCL = pNextCL->getNext();
3333 				}
3334 				if (pNextCL && pNextCL->getContainerType() == FL_CONTAINER_BLOCK)
3335 				{
3336 					pFirstBlock = pBlock;
3337 					pSecondBlock = static_cast <fl_BlockLayout *> (pNextCL);
3338 					if ((pFirstBlock->getNumFrames() > 0) || (pSecondBlock->getNumFrames() > 0))
3339 					{
3340 						b_delBlockWithFrames = true;
3341 					}
3342 				}
3343 			}
3344 		}
3345 
3346 		if (b_delBlockWithFrames)
3347 		{
3348 			_saveAndNotifyPieceTableChange();
3349 			m_pDoc->beginUserAtomicGlob();
3350 			m_pDoc->disableListUpdates();
3351 			b_editStarted = true;
3352 
3353 			UT_sint32 extraHeight = 0;
3354 			bool b_evalHeightOfFirstBlock = false;
3355 			UT_sint32 i = 0;
3356 			UT_sint32 imax = pSecondBlock->getNumFrames();
3357 			for(i=0; i < imax;i++)
3358 			{
3359 				fl_FrameLayout * pFL = pSecondBlock->getNthFrameLayout(i);
3360 				if(pFL->isHidden() > FP_VISIBLE)
3361 					continue;
3362 				if(pFL->getContainerType() != FL_CONTAINER_FRAME)
3363 				{
3364 					UT_ASSERT_HARMLESS(UT_SHOULD_NOT_HAPPEN);
3365 					continue;
3366 				}
3367 				if(pFL->getFramePositionTo() == FL_FRAME_POSITIONED_TO_BLOCK)
3368 				{
3369 					const PP_AttrProp* pAP = NULL;
3370 					const gchar * pszYPos = NULL;
3371 					double ypos = 0.;
3372 					pFL->getAP(pAP);
3373 					if(!pAP || !pAP->getProperty("ypos",pszYPos))
3374 					{
3375 						pszYPos = "0.0in";
3376 					}
3377 					if (!b_evalHeightOfFirstBlock)
3378 					{
3379 						extraHeight = pFirstBlock->getHeightOfBlock(false);
3380 						b_evalHeightOfFirstBlock = true;
3381 					}
3382 					ypos = UT_convertToInches(pszYPos) + double(extraHeight)/double(UT_LAYOUT_RESOLUTION);
3383 					UT_String sValY = UT_formatDimensionString(DIM_IN,ypos);
3384 					const gchar * frameProperties[] = {"ypos",sValY.c_str(),NULL};
3385 					PT_DocPosition posStart = pFL->getPosition(true)+1;
3386 					PT_DocPosition posEnd = posStart;
3387 					UT_DebugOnly<bool> bRet = m_pDoc->changeStruxFmt(PTC_AddFmt,posStart,posEnd,NULL,
3388 																	 frameProperties,PTX_SectionFrame);
3389 					UT_ASSERT(bRet);
3390 				}
3391 			}
3392 			imax = pFirstBlock->getNumFrames();
3393 			for(i=0; i < imax;i++)
3394 			{
3395 				fl_FrameLayout * pFL = pFirstBlock->getNthFrameLayout(0);
3396 				if(pFL->getContainerType() != FL_CONTAINER_FRAME)
3397 				{
3398 					UT_ASSERT_HARMLESS(UT_SHOULD_NOT_HAPPEN);
3399 					break;
3400 				}
3401 				m_pLayout->relocateFrame(pFL,pSecondBlock);
3402 			}
3403 			if (bForward)
3404 			{
3405 				setPoint(pFirstBlock->getPosition()+pFirstBlock->getLength()-1);
3406 			}
3407 			else
3408 			{
3409 				setPoint(pSecondBlock->getPosition());
3410 			}
3411 		}
3412 //
3413 // Code to deal with deleting a footnote reference that embeds a footnote Layout.
3414 //
3415 		if(bForward)
3416 		{
3417 			if(!isInFootnote() && isInFootnote(getPoint() + count))
3418 			{
3419 				fl_FootnoteLayout * pFL = getClosestFootnote(getPoint() + count +1);
3420 				count += pFL->getLength();
3421 			}
3422 			if(!isInEndnote() && isInEndnote(getPoint() + count))
3423 			{
3424 				fl_EndnoteLayout * pEL = getClosestEndnote(getPoint() + count +1);
3425 				count += pEL->getLength();
3426 			}
3427 			if(m_pDoc->isTOCAtPos(getPoint()))
3428 			{
3429 				if(m_pDoc->isTOCAtPos(getPoint()-1))
3430 				{
3431 					m_iInsPoint--;
3432 				}
3433 				count++;
3434 
3435 			}
3436 		}
3437 		else
3438 		{
3439 			if(!isInFootnote(getPoint()) && isInFootnote(getPoint() - count))
3440 			{
3441 				fl_FootnoteLayout * pFL = getClosestFootnote(getPoint());
3442 				count += pFL->getLength();
3443 			}
3444 			else if(isInFootnote(getPoint()))
3445 			{
3446 				if(!isInFootnote(getPoint() - count))
3447 				{
3448 					return;
3449 				}
3450 				else if(!isInFootnote(getPoint() -2))
3451 				{
3452 //
3453 // Don't delete the paragraph strux in footnote
3454 //
3455 					return;
3456 				}
3457 				else if(!isInFootnote(getPoint() -3))
3458 				{
3459 //
3460 // Don't delete the paragraph strux in footnote
3461 //
3462 					return;
3463 				}
3464 			}
3465 			else if(!isInEndnote() && isInEndnote(getPoint() - count))
3466 			{
3467 				fl_EndnoteLayout * pEL = getClosestEndnote(getPoint());
3468 				count += pEL->getLength();
3469 			}
3470 			else if(isInEndnote(getPoint()))
3471 			{
3472 				if(!isInEndnote(getPoint() - count))
3473 				{
3474 					return;
3475 				}
3476 				else if(!isInEndnote(getPoint() -2))
3477 				{
3478 //
3479 // Don't delete the paragraph strux in endnote
3480 //
3481 					return;
3482 				}
3483 				else if(!isInEndnote(getPoint() -3))
3484 				{
3485 //
3486 // Don't delete the paragraph strux in endnote
3487 //
3488 					return;
3489 				}
3490 
3491 			}
3492 			if(m_pDoc->isTOCAtPos(getPoint()-2))
3493 			{
3494 				count +=2;
3495 			}
3496 		}
3497 
3498 		// Code that deals with deleting runs that do not like to be deleted ...  This handles runs
3499 		// that return true for deleteFollowingIfAtInsPoint(). Runs in this category are typically
3500 		// not visible on screen, such as hyperlinks and bookmarks, and are deleted through the main
3501 		// menu. Such runs must not be deleted inadvertedly when pressing delete/backpace. Just to
3502 		// exaplain why: for example, in Word bookmarks inadvertedly disappear when the bookmarked
3503 		// text is edited; this is extremely annoying if such bookmarks are referenced from page
3504 		// reference and similar fields, particularly if the document is long and contains many such
3505 		// fields -- imagine printing a 200+ page document, only to discover that on page 178 you
3506 		// have 'error: bookmark not found' where a page number should have been -- we want to
3507 		// minimise this happening and will only delete such runs when (a) the user explicitely asks
3508 		// to, or (b) they are inside a selection.
3509 		if(!curBlock)
3510 			curBlock = _findBlockAtPosition(getPoint());
3511 
3512 		if(bForward && count == 1)
3513 		{
3514 			UT_return_if_fail( curBlock );
3515 
3516 			fp_Run * pRun = curBlock->findRunAtOffset(getPoint() - curBlock->getPosition());
3517 
3518 			UT_return_if_fail( pRun );
3519 
3520 			UT_uint32 iLength = 0;
3521 			while(pRun && (pRun->deleteFollowingIfAtInsPoint() && (getPoint() == curBlock->getPosition() + pRun->getBlockOffset())))
3522 			{
3523 				iLength += pRun->getLength();
3524 				pRun = pRun->getNextRun();
3525 			}
3526 
3527 			_setPoint(m_iInsPoint + iLength);
3528 
3529 		}
3530 		else if(!bForward && count == 1)
3531 		{
3532 			UT_return_if_fail( curBlock );
3533 
3534 			fp_Run * pRun = curBlock->findRunAtOffset(getPoint() - curBlock->getPosition());
3535 
3536 			UT_return_if_fail( pRun );
3537 
3538 			// back one further
3539 			pRun = pRun->getPrevRun();
3540 
3541 			UT_uint32 iLength = 0;
3542 			while(pRun && (pRun->deleteFollowingIfAtInsPoint() && (getPoint() == curBlock->getPosition() + pRun->getBlockOffset())) )
3543 			{
3544 				iLength += pRun->getLength();
3545 				pRun = pRun->getPrevRun();
3546 			}
3547 
3548 			_setPoint(m_iInsPoint - iLength);
3549 
3550 		}
3551 
3552 		// deal with character clusters, such as base char + vowel + tone mark in Thai
3553 		UT_uint32 pos1 = getPoint();
3554 		if(!bForward)
3555 		{
3556 			UT_ASSERT_HARMLESS( pos1 > count );
3557 			pos1 -= count;
3558 		}
3559 
3560 		_adjustDeletePosition(pos1, count);
3561 
3562 		if(bForward)
3563 			_setPoint(pos1);
3564 		else
3565 			_setPoint(pos1 + count);
3566 
3567 
3568 		// Code to deal with font boundary problem.
3569 		// TODO: This should really be fixed by someone who understands
3570 		// how this code works! In the meantime save current font to be
3571 		// restored after character is deleted.
3572 
3573 		getCharFormat(&props_in);
3574 		currentfont = UT_getAttribute("font-family",props_in);
3575 		properties[1] = currentfont;
3576 		xxx_UT_DEBUGMSG(("deleteSpan - 1: Inital pos %d count %d \n",getPoint(),count));
3577 
3578 		UT_uint32 amt = count;
3579 		UT_uint32 posCur = getPoint();
3580 		UT_uint32 nposCur = getPoint();
3581 		bool fontFlag = false;
3582 
3583 		if (!bForward)
3584 		{
3585 
3586 			if (!_charMotion(bForward,count, false))
3587 			{
3588 				UT_ASSERT(getPoint() <= posCur);
3589 				xxx_UT_DEBUGMSG(("SEVIOR: posCur %d getPoint() %d \n",posCur,getPoint()));
3590 				amt = posCur - getPoint();
3591 			}
3592 
3593 			posCur = getPoint();
3594 			// Code to deal with change of font boundaries:
3595 			if((posCur == nposCur) && (posCur > 0))
3596 			{
3597 				fontFlag = true;
3598 				posCur--;
3599 			}
3600 		}
3601 		else
3602 		{
3603 			PT_DocPosition posEOD;
3604 			UT_DebugOnly<bool> bRes;
3605 
3606 			bRes = getEditableBounds(true, posEOD);
3607 			UT_ASSERT(bRes);
3608 			UT_ASSERT(posCur <= posEOD);
3609 
3610 			if (posEOD < (posCur+amt))
3611 			{
3612 				amt = posEOD - posCur;
3613 			}
3614 		}
3615 
3616 		if(!curBlock)
3617 			curBlock = _findBlockAtPosition(getPoint());
3618 
3619 //
3620 // Code to check for a delete over a frame boundary.
3621 //
3622 		if(isInFrame(posCur) && !isInFrame(posCur+amt))
3623 		{
3624 			fl_FrameLayout * pFL = getFrameLayout(posCur+amt);
3625 			if(pFL != NULL)
3626 			{
3627 			  //
3628 			  // Delete to edge of text box
3629 			  //
3630 			      PT_DocPosition posFrame = pFL->getPosition(true);
3631 			      amt = posFrame + pFL->getLength() - posCur;
3632 			}
3633 			return;
3634 		}
3635 		if(!isInFrame(posCur) && isInFrame(posCur+amt) && (amt > 1))
3636 		{
3637 			fl_FrameLayout * pFL = getFrameLayout(posCur+amt);
3638 			if(pFL != NULL)
3639 			{
3640 			  //
3641 			  // delete to start of text box
3642 			  //
3643 			      PT_DocPosition posFrame = pFL->getPosition(true);
3644 			      amt = posCur + amt + 1 - posFrame;
3645 			}
3646 		}
3647 //
3648 // isInFrame will return true if we're right at the frame strux or right
3649 // at the EndFrame strux. If we delete either we're screwed. Handle
3650 // the cases.
3651 //
3652 // Later we want to be clever about moving the frame into a valid position
3653 // in the new merged block. Just fix the crash for now.
3654 //
3655 		if(m_pDoc->isFrameAtPos(posCur) && isInFrame(posCur+amt)  )
3656 		{
3657 			return;
3658 		}
3659 
3660 		if(m_pDoc->isEndFrameAtPos(posCur))
3661 		{
3662 			return;
3663 		}
3664 
3665 		// Signal PieceTable Change
3666 		if (!b_editStarted)
3667 		{
3668 			_saveAndNotifyPieceTableChange();
3669 			b_editStarted = true;
3670 		}
3671 		if (amt > 0)
3672 		{
3673 			m_pDoc->disableListUpdates();
3674 
3675 			nBlock = _findBlockAtPosition(getPoint());
3676 			fl_AutoNum * pAuto2 = nBlock->getAutoNum();
3677 			if(pAuto2 != NULL )
3678 			{
3679 				pf_Frag_Strux* sdh = nBlock->getStruxDocHandle();
3680 				if((bisList == true) && (pAuto2->getFirstItem() == sdh || pAuto2->getLastItem() == sdh))
3681 				{
3682 					m_pDoc->StopList(sdh);
3683 					PT_DocPosition listPoint,posEOD;
3684 					getEditableBounds(true, posEOD);
3685 					listPoint = getPoint();
3686 					fl_AutoNum * pAuto = nBlock->getAutoNum();
3687 					if(pAuto != NULL)
3688 					{
3689 						if(listPoint + 2 <= posEOD)
3690 							_setPoint(listPoint+2);
3691 						else
3692 							_setPoint(posEOD);
3693 					}
3694 				}
3695 				else if(bisList == true)
3696 				{
3697 
3698 					m_pDoc->deleteSpan(posCur, posCur+amt,NULL, iRealDeleteCount);
3699 					nBlock->remItemFromList();
3700 				}
3701 				else
3702 				{
3703 					m_pDoc->deleteSpan(posCur, posCur+amt,NULL, iRealDeleteCount);
3704 				}
3705 			}
3706 			else
3707 			{
3708 				UT_DEBUGMSG(("deleteSpan - 2: posCur %d amt %d \n",posCur,amt));
3709 				m_pDoc->deleteSpan(posCur, posCur+amt,NULL, iRealDeleteCount);
3710 			}
3711 
3712 			if(fontFlag)
3713 			{
3714 				_makePointLegal();
3715 				setCharFormat(properties);
3716 			}
3717 		}
3718 //
3719 // Dont leave a List field - tab on a line.
3720 //
3721 		if(isTabListAheadPoint())
3722 		{
3723 			UT_uint32 iRealDeleteCount2;
3724 
3725 			m_pDoc->deleteSpan(getPoint(), getPoint()+2,NULL,iRealDeleteCount2);
3726 			iRealDeleteCount += iRealDeleteCount2;
3727 		}
3728 		else if(count == 1)
3729 		{
3730 			bSimple = true;
3731 		}
3732 		// restore updates and clean up dirty lists
3733 		m_pDoc->enableListUpdates();
3734 		m_pDoc->updateDirtyLists();
3735 
3736 		_generalUpdate();
3737 		g_free(props_in);
3738 
3739 		_fixInsertionPointCoords();
3740 		_ensureInsertionPointOnScreen();
3741 
3742 		//special handling is required for delete in revisions mode
3743 		//where we have to move the insertion point
3744 		// only if we are deleting forward; if deleting backwards, the
3745 		// code above already moved the insertion point
3746 		//
3747 		// Tomas, Oct 28, 2003
3748 		// do this if we deleted fewer than count characters
3749 		if(bForward && isMarkRevisions() && (iRealDeleteCount < count))
3750 		{
3751 			UT_ASSERT( iRealDeleteCount <= count );
3752 			_charMotion(bForward,count - iRealDeleteCount);
3753 		}
3754 		if (b_delBlockWithFrames)
3755 		{
3756 			m_pDoc->endUserAtomicGlob();
3757 		}
3758 	}
3759 
3760 	// Signal PieceTable Changes have finished
3761 	_restorePieceTableState();
3762 	_setPoint(getPoint());
3763 	if(!bSimple)
3764 		notifyListeners(AV_CHG_MOTION | AV_CHG_ALL);
3765 	else
3766 		notifyListeners(AV_CHG_MOTION);
3767 
3768 }
3769 
3770 
3771 
cmdScroll(AV_ScrollCmd cmd,UT_uint32 iPos)3772 void FV_View::cmdScroll(AV_ScrollCmd cmd, UT_uint32 iPos)
3773 {
3774 
3775 #define HACK_LINE_HEIGHT				20 // TODO Fix this!!
3776 
3777 	UT_sint32 lineHeight = iPos;
3778 	bool bVertical = false;
3779 	bool bHorizontal = false;
3780 
3781 	if (lineHeight == 0)
3782 		lineHeight = m_pG->tlu(HACK_LINE_HEIGHT);
3783 
3784 	UT_sint32 yoff = m_yScrollOffset;
3785 	UT_sint32 xoff = m_xScrollOffset;
3786 
3787 	switch(cmd)
3788 	{
3789 	case AV_SCROLLCMD_PAGEDOWN:
3790 		yoff += getWindowHeight();
3791 		bVertical = true;
3792 		break;
3793 	case AV_SCROLLCMD_PAGEUP:
3794 		yoff -= getWindowHeight();
3795 		bVertical = true;
3796 		break;
3797 	case AV_SCROLLCMD_PAGELEFT:
3798 		xoff -= getWindowWidth();
3799 		bHorizontal = true;
3800 		break;
3801 	case AV_SCROLLCMD_PAGERIGHT:
3802 		xoff += getWindowWidth();
3803 		bHorizontal = true;
3804 		break;
3805 	case AV_SCROLLCMD_LINEDOWN:
3806 		yoff += lineHeight;
3807 		bVertical = true;
3808 		break;
3809 	case AV_SCROLLCMD_LINEUP:
3810 		yoff -= lineHeight;
3811 		bVertical = true;
3812 		break;
3813 	case AV_SCROLLCMD_LINELEFT:
3814 		xoff -= lineHeight;
3815 		bHorizontal = true;
3816 		break;
3817 	case AV_SCROLLCMD_LINERIGHT:
3818 		xoff += lineHeight;
3819 		bHorizontal = true;
3820 		break;
3821 	case AV_SCROLLCMD_TOTOP:
3822 		yoff = 0;
3823 		bVertical = true;
3824 		break;
3825 	case AV_SCROLLCMD_TOPOSITION:
3826 		UT_ASSERT(UT_NOT_IMPLEMENTED);
3827 		break;
3828 	case AV_SCROLLCMD_TOBOTTOM:
3829 		fp_Page* pPage = m_pLayout->getFirstPage();
3830 		UT_sint32 iDocHeight = getPageViewTopMargin();
3831 		while (pPage)
3832 		{
3833 			iDocHeight += pPage->getHeight() + getPageViewSep();
3834 			pPage = pPage->getNext();
3835 		}
3836 		yoff = iDocHeight;
3837 		bVertical = true;
3838 		break;
3839 	}
3840 
3841 	if (yoff < 0)
3842 		yoff = 0;
3843 
3844 	bool bRedrawPoint = true;
3845 
3846 	if (bVertical && (yoff != m_yScrollOffset))
3847 	{
3848 		sendVerticalScrollEvent(yoff);
3849 		if ((cmd != AV_SCROLLCMD_PAGEUP
3850 			 && cmd != AV_SCROLLCMD_PAGEDOWN))
3851 		  bRedrawPoint = false;
3852 //		UT_ASSERT(m_yScrollOffset == m_pG->getPrevYOffset());
3853 	}
3854 
3855 	if (xoff < 0)
3856 		xoff = 0;
3857 
3858 	if (bHorizontal && (xoff != m_xScrollOffset))
3859 	{
3860 		sendHorizontalScrollEvent(xoff);
3861 		bRedrawPoint = false;
3862 	}
3863 
3864 	if (bRedrawPoint)
3865 		_fixInsertionPointCoords();
3866 
3867 }
3868 
cmdSelectNoNotify(PT_DocPosition dpBeg,PT_DocPosition dpEnd)3869 bool FV_View::cmdSelectNoNotify(PT_DocPosition dpBeg, PT_DocPosition dpEnd)
3870 {
3871 	if (!isSelectionEmpty())
3872 	{
3873 		_clearSelection();
3874 	}
3875 	_setPoint(dpBeg);
3876 	_setSelectionAnchor();
3877 	m_Selection.setSelectionLeftAnchor(dpBeg);
3878 	if(dpBeg < dpEnd - 2)
3879 	{
3880 	     if(m_pDoc->isTableAtPos(dpEnd) && m_pDoc->isEndTableAtPos(dpEnd-1))
3881 	     {
3882 	          dpEnd--;
3883 	     }
3884 	     if(m_pDoc->isCellAtPos(dpEnd))
3885 	     {
3886 	          dpEnd--;
3887 	     }
3888 	}
3889 	m_Selection.setSelectionRightAnchor(dpEnd);
3890 	_setPoint (dpEnd);
3891 // This is no good in abicommand
3892 //	UT_ASSERT(!isSelectionEmpty());
3893 
3894 	if (dpBeg == dpEnd)
3895 	{
3896 		return false;
3897 	}
3898 	return true;
3899 }
3900 
cmdSelect(PT_DocPosition dpBeg,PT_DocPosition dpEnd)3901 void FV_View::cmdSelect(PT_DocPosition dpBeg, PT_DocPosition dpEnd)
3902 {
3903 	if(cmdSelectNoNotify(dpBeg, dpEnd))
3904 	{
3905 		_drawSelection();
3906 		notifyListeners(AV_CHG_EMPTYSEL);
3907 	}
3908 }
3909 
cmdSelect(const std::pair<PT_DocPosition,PT_DocPosition> & range)3910 void FV_View::cmdSelect( const std::pair< PT_DocPosition, PT_DocPosition >& range )
3911 {
3912 	if( range.first == 0 && range.second == 0 )
3913 	{
3914 		cmdUnselectSelection();
3915 		return;
3916 	}
3917 
3918 	cmdSelect( range.first, range.second );
3919 }
3920 
3921 
3922 
3923 #define IS_SELECTALL(a, b) ((a) == FV_DOCPOS_BOD && (b) == FV_DOCPOS_EOD)
3924 
cmdSelect(UT_sint32 xPos,UT_sint32 yPos,FV_DocPos dpBeg,FV_DocPos dpEnd)3925 void FV_View::cmdSelect(UT_sint32 xPos, UT_sint32 yPos, FV_DocPos dpBeg, FV_DocPos dpEnd)
3926 {
3927 	UT_DEBUGMSG(("Double click on mouse \n"));
3928 
3929 	warpInsPtToXY(xPos, yPos,true);
3930 	PT_DocPosition iPosLeft = _getDocPos(dpBeg, false);
3931 	PT_DocPosition iPosRight = _getDocPos(dpEnd, false);
3932 	if(iPosLeft > iPosRight)
3933 	{
3934 		return;
3935 	}
3936 	if(!isInFrame(iPosLeft) && isInFrame(iPosRight))
3937 	{
3938 		fl_FrameLayout * pFL = getFrameLayout(iPosRight);
3939 		iPosRight =pFL->getPosition(true)-1;
3940 	}
3941 	if(isInFrame(iPosLeft) && !isInFrame(iPosRight))
3942 	{
3943 		fl_FrameLayout * pFL = getFrameLayout(iPosLeft);
3944 		iPosRight =pFL->getPosition(true) + pFL->getLength() -1;
3945 	}
3946 	if(iPosLeft == iPosRight) return;
3947 //
3948 // Code to select a paragraph break on selectLine if on first line of a Block.
3949 //
3950 	bool bRedraw = false;
3951 	if((dpBeg == FV_DOCPOS_BOL) || (dpBeg == FV_DOCPOS_BOP) || (dpBeg == FV_DOCPOS_BOD))
3952 	{
3953 		fl_BlockLayout * pBlock =  _findBlockAtPosition(iPosLeft);
3954 		if(pBlock)
3955 		{
3956 			UT_sint32 x, y, x2, y2, h;
3957 			bool b;
3958 			fp_Run* pRun = pBlock->findPointCoords(m_iInsPoint, false, x, y, x2, y2, h, b);
3959 			if(pRun)
3960 			{
3961 				fp_Line * pLine = pRun->getLine();
3962 				if(pLine == static_cast<fp_Line *>(pBlock->getFirstContainer()))
3963 				{
3964 					PT_DocPosition iPosNew = pBlock->getPosition() -1;
3965 					if(iPosNew < iPosLeft)
3966 					{
3967 						iPosLeft = iPosNew;
3968 					}
3969 					bRedraw = true; // Need to trick a global redraw in
3970 					// header/footer
3971 				}
3972 			}
3973 		}
3974 	}
3975 	cmdSelect (iPosLeft, iPosRight);
3976 	if(bRedraw && isHdrFtrEdit())
3977 	{
3978 		cmdSelect (iPosLeft+1, iPosRight);
3979 	}
3980 }
3981 
cmdHyperlinkJump(UT_sint32 xPos,UT_sint32 yPos)3982 void FV_View::cmdHyperlinkJump(UT_sint32 xPos, UT_sint32 yPos)
3983 {
3984 	_clearSelection();
3985 	warpInsPtToXY(xPos, yPos,true);
3986 
3987 	fl_BlockLayout * pBlock = getCurrentBlock();
3988 	PT_DocPosition iRelPos = getPoint() - pBlock->getPosition(false);
3989 
3990 	fp_Run *pRun = pBlock->getFirstRun();
3991 	while (pRun && pRun->getBlockOffset()+ pRun->getLength() < iRelPos)
3992 		pRun= pRun->getNextRun();
3993 
3994 	UT_return_if_fail(pRun);
3995 	pRun->getPrevRun();
3996 
3997 	UT_return_if_fail(pRun);
3998 #if 0
3999 	if(pRun->getType()== FPRUN_FMTMARK || pRun->getType()== FPRUN_HYPERLINK || pRun->getType()== FPRUN_BOOKMARK)
4000 		pRun  = pRun->getNextRun();
4001 
4002 	UT_ASSERT(pRun);
4003 #endif
4004 	fp_HyperlinkRun * pH = pRun->getHyperlink();
4005 
4006 	UT_return_if_fail(pH);
4007 
4008 	const gchar * pTarget = pH->getTarget();
4009 
4010 	if(*pTarget == '#')
4011 		pTarget++;
4012 
4013 	UT_UCS4String pJump(pTarget);
4014 
4015 	gotoTarget(AP_JUMPTARGET_BOOKMARK, pJump.ucs4_str());
4016 }
4017 
4018 
cmdHyperlinkJump(PT_DocPosition pos)4019 void FV_View::cmdHyperlinkJump(PT_DocPosition pos)
4020 {
4021 	fp_HyperlinkRun * pH = static_cast<fp_HyperlinkRun *>(getHyperLinkRun(pos));
4022 	UT_return_if_fail(pH);
4023 	if(pH->getHyperlinkType() == HYPERLINK_ANNOTATION)
4024 	{
4025 		fp_AnnotationRun * pAN = static_cast<fp_AnnotationRun *>(pH);
4026 		if(!pAN->displayAnnotations())
4027 		{
4028 			UT_DEBUGMSG(("Can only directly edit if we in show annotation mode \n"));
4029 			UT_DEBUGMSG(("Should pop up a dialog to say this, but not now \n?"));
4030 			return;
4031 		}
4032 		UT_uint32 aid = pAN->getPID();
4033 		fl_AnnotationLayout * pAL = getAnnotationLayout(aid);
4034 		if(pAL == NULL)
4035 		{
4036 			return;
4037 		}
4038 		//
4039 		// Put caret just past the annotation field
4040 		//
4041 		PT_DocPosition posAn = pAL->getPosition();
4042 		setPoint(posAn);
4043 		_fixInsertionPointCoords();
4044 		_ensureInsertionPointOnScreen();
4045 		notifyListeners(AV_CHG_MOTION);
4046 		_generalUpdate();
4047 		return;
4048 	}
4049 	const gchar * pTarget = pH->getTarget();
4050 
4051 	if(*pTarget == '#')
4052 		pTarget++;
4053 
4054 	UT_UCS4String pJump(pTarget);
4055 
4056 	gotoTarget(AP_JUMPTARGET_BOOKMARK, pJump.ucs4_str());
4057 }
4058 
cmdHyperlinkCopyLocation(PT_DocPosition pos)4059 void FV_View::cmdHyperlinkCopyLocation(PT_DocPosition pos)
4060 {
4061 	fp_HyperlinkRun * pH = static_cast<fp_HyperlinkRun *>(getHyperLinkRun(pos));
4062 	if(!pH)
4063 		return;
4064 
4065 	const gchar * pTarget = pH->getTarget();
4066 
4067 	if(!pTarget || !*pTarget || !strcmp(pTarget,"#"))
4068 		return;
4069 
4070 	//skip over internal anchors
4071 	if(*pTarget == '#')
4072 		pTarget++;
4073 
4074 	//copy the target to the clipboard
4075 	copyTextToClipboard(pTarget, true);
4076 }
4077 
4078 
cmdUndo(UT_uint32 count)4079 void FV_View::cmdUndo(UT_uint32 count)
4080 {
4081 	STD_DOUBLE_BUFFERING_FOR_THIS_FUNCTION
4082 
4083 	if (!isSelectionEmpty())
4084 		_clearSelection();
4085 
4086 	// Temporarily disable smart quotes
4087 	// This allows the smart quote to be reverted by undo.
4088 	m_bAllowSmartQuoteReplacement = false;
4089 
4090 	// Signal PieceTable Change
4091 	m_pDoc->notifyPieceTableChangeStart();
4092 
4093 	// Turn off list updates
4094 	m_pDoc->disableListUpdates();
4095 
4096 // Don't update tables until finished
4097 
4098 	m_pDoc->setDontImmediatelyLayout(true);
4099 
4100 	// Remember the current position, We might need it later.
4101 	rememberCurrentPosition();
4102 	UT_DEBUGMSG(("SEVIOR: undoing %d operations \n",count));
4103 	m_pDoc->undoCmd(count);
4104 	allowChangeInsPoint();
4105 	m_pDoc->setDontImmediatelyLayout(false);
4106 
4107 //
4108 // Now do a general update to make everything look good again.
4109 //
4110 	_generalUpdate();
4111 
4112 	notifyListeners(AV_CHG_DIRTY);
4113 
4114 // Look to see if we need the saved insertion point after the undo
4115 // 	if(needSavedPosition())
4116 // 	{
4117 //
4118 // We do, so restore insertion point to that value.
4119 // 		_setPoint(getSavedPosition());
4120 // 		clearSavedPosition();
4121 // 	}
4122 	// restore updates and clean up dirty lists
4123 	m_pDoc->enableListUpdates();
4124 	m_pDoc->updateDirtyLists();
4125 
4126 	// Signal PieceTable Changes have finished
4127 	m_pDoc->notifyPieceTableChangeEnd();
4128 	m_iPieceTableState = 0;
4129 	// Move insertion point out of field run if it is in one
4130 	//
4131 	_charMotion(true, 0);
4132 //
4133 // Do a complete update coz who knows what happened in the undo!
4134 //
4135 	notifyListeners(AV_CHG_ALL);
4136 	PT_DocPosition posEnd = 0;
4137 	PT_DocPosition posBOD = 0;
4138 	getEditableBounds(true, posEnd);
4139 	getEditableBounds(true, posBOD);
4140 	bool bOK = true;
4141 	while(bOK && !isPointLegal() && (getPoint() < posEnd))
4142 	{
4143 		bOK = _charMotion(true,1);
4144 	}
4145 
4146 	bOK = true;
4147 	while(bOK && !isPointLegal() && (getPoint() > posBOD))
4148 	{
4149 		bOK = _charMotion(false,1);
4150 	}
4151 	setCursorToContext();
4152 
4153 	_updateInsertionPoint();
4154 
4155 	// Reenable smart quotes
4156 	m_bAllowSmartQuoteReplacement = true;
4157 }
4158 
cmdRedo(UT_uint32 count)4159 void FV_View::cmdRedo(UT_uint32 count)
4160 {
4161 	STD_DOUBLE_BUFFERING_FOR_THIS_FUNCTION
4162 
4163 	if (!isSelectionEmpty())
4164 		_clearSelection();
4165 
4166 	// Temporarily disable smart quotes
4167 	// This allows the smart quote to be reverted by undo.
4168 	m_bAllowSmartQuoteReplacement = false;
4169 
4170 	// Signal PieceTable Change
4171 	m_pDoc->notifyPieceTableChangeStart();
4172 
4173 	// Turn off list updates
4174 	m_pDoc->disableListUpdates();
4175 	m_pDoc->setDontImmediatelyLayout(true);
4176 
4177 	// Remember the current position, We might need it later.
4178 	rememberCurrentPosition();
4179 
4180 	m_pDoc->redoCmd(count);
4181 	allowChangeInsPoint();
4182 
4183 // Look to see if we need the saved insertion point after the undo
4184 // 	if(needSavedPosition())
4185 // 	{
4186 //
4187 // We do, so restore insertion point to that value.
4188 //
4189 // 		_setPoint(getSavedPosition());
4190 // 		clearSavedPosition();
4191 // 	}
4192 	m_pDoc->setDontImmediatelyLayout(false);
4193 
4194 	// Signal PieceTable Changes have finished
4195 	m_pDoc->notifyPieceTableChangeEnd();
4196 	m_iPieceTableState = 0;
4197 
4198 	// restore updates and clean up dirty lists
4199 	m_pDoc->enableListUpdates();
4200 	m_pDoc->updateDirtyLists();
4201 
4202 	_generalUpdate();
4203 
4204 //
4205 // Do a complete update coz who knows what happened in the undo!
4206 //
4207 	PT_DocPosition posEnd = 0;
4208 	getEditableBounds(true, posEnd);
4209 	bool bOK = true;
4210 	bool bMoved = false;
4211 	while(bOK && !isPointLegal() && (getPoint() < posEnd))
4212 	{
4213 		bOK = _charMotion(true,1);
4214 		bMoved = true;
4215 	}
4216 	if(getPoint() > posEnd)
4217 	{
4218 		setPoint(posEnd);
4219 		bMoved = true;
4220 	}
4221 
4222 	bOK = true;
4223 	while(bOK && !isPointLegal() && (getPoint() > 2))
4224 	{
4225 		bOK = _charMotion(false,1);
4226 		bMoved = true;
4227 	}
4228 	if(!bMoved && (getPoint() != posEnd) )
4229 	{
4230 		bOK = _charMotion(true,1);
4231 		bOK = _charMotion(false,1);
4232 	}
4233 
4234 	setCursorToContext();
4235 	_updateInsertionPoint();
4236 	notifyListeners(AV_CHG_ALL);
4237 
4238 	// Reenable smart quotes
4239 	m_bAllowSmartQuoteReplacement = true;
4240 }
4241 
cmdSave(void)4242 UT_Error FV_View::cmdSave(void)
4243 {
4244 	// transfer any persistent properties into the doc
4245 	const gchar ** ppProps = getViewPersistentProps();
4246 	m_pDoc->setProperties(ppProps);
4247 	_updateDatesBeforeSave(false);
4248 
4249 	UT_Error tmpVar;
4250 	tmpVar = m_pDoc->save();
4251 	if (!tmpVar)
4252 	{
4253 		notifyListeners(AV_CHG_SAVE);
4254 	}
4255 	return tmpVar;
4256 }
4257 
cmdSaveAs(const char * szFilename,int ieft,bool cpy)4258 UT_Error FV_View::cmdSaveAs(const char * szFilename, int ieft, bool cpy)
4259 {
4260 	// transfer any persistent properties into the doc
4261 	const gchar ** ppProps = getViewPersistentProps();
4262 	m_pDoc->setProperties(ppProps);
4263 	_updateDatesBeforeSave(true);
4264 
4265 	UT_Error tmpVar;
4266 	tmpVar = static_cast<AD_Document*>(m_pDoc)->saveAs(szFilename, ieft, cpy);
4267 	if (!tmpVar && cpy)
4268 	{
4269 		notifyListeners(AV_CHG_SAVE);
4270 	}
4271 	return tmpVar;
4272 }
4273 
cmdSaveAs(const char * szFilename,int ieft)4274 UT_Error FV_View::cmdSaveAs(const char * szFilename, int ieft)
4275 {
4276   return cmdSaveAs(szFilename, ieft, true);
4277 }
4278 
4279 
cmdCut(void)4280 void FV_View::cmdCut(void)
4281 {
4282 	if (isSelectionEmpty())
4283 	{
4284 		// clipboard does nothing if there is no selection
4285 		return;
4286 	}
4287 	if(m_Selection.getSelectionMode() == FV_SelectionMode_TableColumn)
4288 	{
4289 		PD_DocumentRange * pDR = m_Selection.getNthSelection(0);
4290 		PT_DocPosition pos = 0;
4291 		if(pDR)
4292 		{
4293 		    pos = pDR->m_pos1 +1;
4294 		}
4295 		else
4296 		{
4297 		    pos = getSelectionAnchor();
4298 		    if(pos > getPoint())
4299 		    {
4300 			pos = getPoint();
4301 		    }
4302 		}
4303 		_clearSelection();
4304 		cmdDeleteCol(pos);
4305 		return;
4306 	}
4307 	if(m_Selection.getSelectionMode() == FV_SelectionMode_TableRow)
4308 	{
4309 		PD_DocumentRange * pDR = m_Selection.getNthSelection(0);
4310 		PT_DocPosition pos = 0;
4311 		if(pDR)
4312 		{
4313 		    pos = pDR->m_pos1 +1;
4314 		}
4315 		else
4316 		{
4317 		    pos = getSelectionAnchor();
4318 		    if(pos > getPoint())
4319 		    {
4320 			pos = getPoint();
4321 		    }
4322 		}
4323 		_clearSelection();
4324 		cmdDeleteRow(pos);
4325 		return;
4326 	}
4327 	// Signal PieceTable Change
4328 	m_pDoc->notifyPieceTableChangeStart();
4329 
4330 	//
4331 	// Disable list updates until after we've finished
4332 	//
4333 	m_pDoc->disableListUpdates();
4334 	cmdCopy(true);
4335 	_deleteSelection();
4336 
4337 	// Signal PieceTable Changes have finished
4338 	m_pDoc->notifyPieceTableChangeEnd();
4339 	m_iPieceTableState = 0;
4340 	_generalUpdate();
4341 
4342 	// restore updates and clean up dirty lists
4343 	m_pDoc->enableListUpdates();
4344 	m_pDoc->updateDirtyLists();
4345 
4346 	_setPoint(getPoint());
4347 	_fixInsertionPointCoords();
4348 	_ensureInsertionPointOnScreen();
4349 	notifyListeners(AV_CHG_ALL);
4350 
4351 	m_SelectionHandles.hide();
4352 }
4353 
4354 // bToClipboard is true if you want to copy to the CLIPBOARD
4355 // selection on UNIX, as opposed to some PRIMARY selection
cmdCopy(bool bToClipboard)4356 void FV_View::cmdCopy(bool bToClipboard)
4357 {
4358 	if (isSelectionEmpty())
4359 	{
4360 		// clipboard does nothing if there is no selection
4361 		return;
4362 	}
4363 
4364 	PD_DocumentRange dr;
4365 	getDocumentRangeOfCurrentSelection(&dr);
4366 	m_pApp->copyToClipboard(&dr, bToClipboard);
4367 	notifyListeners(AV_CHG_CLIPBOARD);
4368 }
4369 
cmdPaste(bool bHonorFormatting)4370 void FV_View::cmdPaste(bool bHonorFormatting)
4371 {
4372 //
4373 // Look to see if should paste a table column or row
4374 //
4375 
4376 	STD_DOUBLE_BUFFERING_FOR_THIS_FUNCTION
4377 
4378 	if((m_Selection.getPrevSelectionMode() == FV_SelectionMode_TableColumn)
4379 	   || (m_Selection.getPrevSelectionMode() == 	FV_SelectionMode_TableRow))
4380 	{
4381 		if(isInTable())
4382 		{
4383 			fl_TableLayout * pTab = getTableAtPos(getPoint());
4384 			if(pTab && pTab == m_Selection.getTableLayout())
4385 			{
4386 				m_Selection.pasteRowOrCol();
4387 
4388 				// FIXME does this section get affected
4389 				// by scrolling too?
4390 
4391 				return;
4392 			}
4393 		}
4394 	}
4395 
4396 	// set UAG markers around everything that the actual paste does
4397 	// so that undo/redo will treat it as one step.
4398 
4399 	m_pDoc->beginUserAtomicGlob();
4400 
4401 	// Signal PieceTable Change
4402 	m_pDoc->notifyPieceTableChangeStart();
4403 
4404 	//
4405 	// Disable list updates until after we've finished
4406 	//
4407 	m_pDoc->disableListUpdates();
4408 	m_pDoc->setDoingPaste();
4409 	setCursorWait();
4410 	m_pDoc->setDontImmediatelyLayout(true);
4411 	_doPaste(true, bHonorFormatting);
4412 	// restore updates and clean up dirty lists
4413 	m_pDoc->enableListUpdates();
4414 	m_pDoc->updateDirtyLists();
4415 	clearCursorWait();
4416 
4417 	// Signal PieceTable Changes have finished
4418 	m_pDoc->notifyPieceTableChangeEnd();
4419 	m_iPieceTableState = 0;
4420 
4421 	m_pDoc->clearDoingPaste();
4422 	m_pDoc->endUserAtomicGlob();
4423 	m_iPieceTableState = 0;
4424 	// Move insertion point out of field run if it is in one
4425 	//
4426 	_charMotion(true, 0);
4427 	_makePointLegal();
4428 //
4429 // Do a complete update coz who knows what happened in the paste!
4430 //
4431 
4432 	// force update the screen before leaving the current view
4433 
4434 	_fixInsertionPointCoords();
4435 	_ensureInsertionPointOnScreen();
4436 	notifyListeners(AV_CHG_ALL);
4437 
4438 }
4439 
cmdPasteSelectionAt(UT_sint32 xPos,UT_sint32 yPos)4440 void FV_View::cmdPasteSelectionAt(UT_sint32 xPos, UT_sint32 yPos)
4441 {
4442 	// this is intended for the X11 middle mouse paste trick.
4443 	//
4444 	// if this view has the selection, we need to remember it
4445 	// before we warp to the given (x,y) -- or else there won't
4446 	// be a selection to paste when get there.	this is sort of
4447 	// back door hack and should probably be re-thought.
4448 
4449 	// set UAG markers around everything that the actual paste does
4450 	// so that undo/redo will treat it as one step.
4451 
4452 	m_pDoc->beginUserAtomicGlob();
4453 
4454 	// Signal PieceTable Change
4455 	_saveAndNotifyPieceTableChange();
4456 
4457 	if (!isSelectionEmpty())
4458 		m_pApp->cacheCurrentSelection(this);
4459 	cmdCopy(false);
4460 	warpInsPtToXY(xPos,yPos,true);
4461 	_doPaste(false, true);
4462 	m_pApp->cacheCurrentSelection(NULL);
4463 
4464 	// Signal PieceTable Changes have finished
4465 	_restorePieceTableState();
4466 	_fixInsertionPointCoords();
4467 	_ensureInsertionPointOnScreen();
4468 
4469 	m_pDoc->endUserAtomicGlob();
4470 	m_prevMouseContext =  EV_EMC_TEXT;
4471 	notifyListeners(AV_CHG_ALL);
4472 }
4473 
cmdDeleteBookmark(const char * szName)4474 UT_Error FV_View::cmdDeleteBookmark(const char* szName)
4475 {
4476 	return _deleteBookmark(szName, true);
4477 }
4478 
cmdDeleteHyperlink()4479 UT_Error FV_View::cmdDeleteHyperlink()
4480 {
4481 	PT_DocPosition pos = getPoint();
4482 	UT_DEBUGMSG(("fv_View::cmdDeleteHyperlink: pos %d\n", pos));
4483 	UT_Error err= _deleteHyperlink(pos,true);
4484 	m_prevMouseContext =  EV_EMC_TEXT;
4485 	setCursorToContext();
4486 	notifyListeners(AV_CHG_ALL);
4487 	return err;
4488 }
4489 
4490 
cmdHyperlinkStatusBar(UT_sint32 xPos,UT_sint32 yPos)4491 UT_Error FV_View::cmdHyperlinkStatusBar(UT_sint32 xPos, UT_sint32 yPos)
4492 {
4493 	UT_sint32 xClick, yClick;
4494 	fp_Page* pPage = _getPageForXY(xPos, yPos, xClick, yClick);
4495 
4496 	PT_DocPosition pos;
4497 	bool bBOL = false;
4498 	bool bEOL = false;
4499 	bool isTOC = false;
4500 	pPage->mapXYToPosition(xClick, yClick, pos, bBOL, bEOL,isTOC);
4501 
4502 	// now get the run at the position and the hyperlink run
4503 	fp_HyperlinkRun * pH1 = 0;
4504 
4505 	fl_BlockLayout *pBlock = _findBlockAtPosition(pos);
4506 	PT_DocPosition curPos = pos - pBlock->getPosition(false);
4507 
4508 	fp_Run * pRun = pBlock->getFirstRun();
4509 
4510 	//find the run at pos1
4511 	while(pRun && pRun->getBlockOffset() <= curPos)
4512 		pRun = pRun->getNextRun();
4513 
4514 	// this sometimes happens, not sure why
4515 	//UT_ASSERT(pRun);
4516 	if(!pRun)
4517 		return false;
4518 
4519 	// now we have the run immediately after the run in question, so
4520 	// we step back
4521 	pRun = pRun->getPrevRun();
4522 	UT_ASSERT(pRun);
4523 	if(!pRun)
4524 		return false;
4525 
4526 	xxx_UT_DEBUGMSG(("fv_View::cmdHyperlinkStatusBar: run 0x%x, type %d\n", pRun,pRun->getType()));
4527 	pH1 = pRun->getHyperlink();
4528 
4529 	// this happens after a deletion of a hyperlink
4530 	// the mouse processing is in the state of belief
4531 	// that the processing has not finished yet -- this is not specific
4532 	// to hyperlinks, it happens with anything on the context menu, except
4533 	// it goes unobserved since the cursor does not change
4534 	//UT_ASSERT(pH1);
4535 	if(!pH1)
4536 		return false;
4537 	xxx_UT_DEBUGMSG(("fv_View::cmdHyperlinkStatusBar: msg [%s]\n",pH1->getTarget()));
4538 	XAP_Frame * pFrame = static_cast<XAP_Frame *> (getParentData());
4539 	if(pH1->getHyperlinkType() ==  HYPERLINK_NORMAL)
4540 	{
4541 	    UT_UTF8String url = pH1->getTarget();
4542 	    url.decodeURL();
4543 	    pFrame->setStatusMessage(url.utf8_str());
4544 	}
4545 	else
4546 	{
4547 	    if(!isAnnotationPreviewActive())
4548 	    {
4549 	         UT_DEBUGMSG(("popup Annotation preview \n"));
4550 	    }
4551 	}
4552 	return true;
4553 }
4554 
cmdEditAnnotationWithDialog(UT_uint32 aID)4555 bool FV_View::cmdEditAnnotationWithDialog(UT_uint32 aID)
4556 {
4557 	// kill the annotation preview popup if needed
4558 	if(isAnnotationPreviewActive())
4559 		killAnnotationPreview();
4560 
4561 	//
4562 	// Get the text fromt he annotation
4563 	//
4564 
4565 	// TODO maybe we should not exit if annotation is not present (ex. auto-generated annotations may become not be editable!)
4566 	std::string sText;
4567 	std::string sTitle2;
4568 	std::string sAuthor2;
4569 	bool b = getAnnotationText(aID,sText);
4570 	if(!b)
4571 		return false;
4572 
4573 	// Optional fields
4574 	getAnnotationTitle(aID,sTitle2);
4575 	getAnnotationAuthor(aID,sAuthor2);
4576 
4577 	// edit annotation
4578 
4579 	XAP_Frame * pFrame = static_cast<XAP_Frame *> (getParentData());
4580 	UT_return_val_if_fail(pFrame, false);
4581 
4582 	XAP_App * pApp = XAP_App::getApp();
4583 	UT_return_val_if_fail (pApp, false);
4584 
4585 	pFrame->raise();
4586 
4587 	XAP_DialogFactory * pDialogFactory
4588 		= static_cast<XAP_DialogFactory *>(pFrame->getDialogFactory());
4589 
4590 	AP_Dialog_Annotation * pDialog
4591 		= static_cast<AP_Dialog_Annotation *>(pDialogFactory->requestDialog(AP_DIALOG_ID_ANNOTATION));
4592 	UT_return_val_if_fail (pDialog, false);
4593 
4594 	// set initial annotation properties
4595 	// TODO add support for all fields
4596 	pDialog->setTitle(sTitle2);
4597 	pDialog->setAuthor(sAuthor2);
4598 	pDialog->setDescription(sText);
4599 
4600 	// run the dialog
4601 
4602 	UT_DEBUGMSG(("cmdEditAnnotationWithDialog: Drawing annotation dialog...\n"));
4603 	pDialog->runModal(pFrame);
4604 	bool bOK = (pDialog->getAnswer() == AP_Dialog_Annotation::a_OK);
4605 	bool bApply = (pDialog->getAnswer() == AP_Dialog_Annotation::a_APPLY);
4606 	fl_AnnotationLayout * pAL = NULL;
4607 
4608 	if (bOK)
4609 	{
4610 		UT_DEBUGMSG(("cmdEditAnnotationWithDialog: Annotation id(\"%d\") edited \n",aID));
4611 
4612 		for(UT_sint32 i = 0;i < pApp->getFrameCount();++i)
4613 		{
4614 			pApp->getFrame(i)->updateTitle ();
4615 		}
4616 
4617 		const std::string & sDescr = pDialog->getDescription();
4618 		const std::string & sTitle = pDialog->getTitle();
4619 		const std::string & sAuthor = pDialog->getAuthor();
4620 //		bool bReplaceSelection = false;
4621 
4622 		b = setAnnotationText(aID,sDescr,sAuthor,sTitle);
4623 	}
4624 	else if (bApply)
4625 	{
4626 		pAL = insertAnnotationDescription(aID, pDialog);
4627 		UT_return_val_if_fail(pAL, false);
4628 	}
4629 	// release the dialog
4630 	pDialogFactory->releaseDialog(pDialog);
4631 	//
4632 	// Select the text
4633 	//
4634 	pAL = getAnnotationLayout(aID);
4635 	if(!pAL)
4636 	  return false;
4637 	selectAnnotation(pAL);
4638 
4639 	return true;
4640 }
4641 
insertAnnotationDescription(UT_uint32 aID,AP_Dialog_Annotation * pDialog)4642 fl_AnnotationLayout *FV_View::insertAnnotationDescription(UT_uint32 aID, AP_Dialog_Annotation *pDialog)
4643 {
4644 	fl_AnnotationLayout *pAL = getAnnotationLayout(aID);
4645 	UT_return_val_if_fail(pAL, NULL);
4646 
4647 	UT_UCS4String sDescr(pDialog->getDescription());
4648 	pf_Frag_Strux *sdhAnn = pAL->getStruxDocHandle();
4649 	pf_Frag_Strux *sdhEnd = NULL;
4650 
4651 	getDocument()->getNextStruxOfType(sdhAnn, PTX_EndAnnotation, &sdhEnd);
4652 	UT_return_val_if_fail(sdhEnd, NULL);
4653 
4654 	// Start of the text covered by the annotations
4655 	PT_DocPosition posStart = getDocument()->getStruxPosition(sdhEnd);
4656 	posStart++;
4657 
4658 	fp_Run *pRun = getHyperLinkRun(posStart);
4659 	UT_return_val_if_fail(pRun, NULL);
4660 
4661 	pRun = pRun->getNextRun();
4662 	while (pRun && (pRun->getType() != FPRUN_HYPERLINK))
4663 		pRun = pRun->getNextRun();
4664 	UT_return_val_if_fail(pRun, NULL);
4665 	UT_return_val_if_fail(pRun->getType() == FPRUN_HYPERLINK, NULL);
4666 
4667 	PT_DocPosition posEnd = pRun->getBlock()->getPosition(false) + pRun->getBlockOffset();
4668 
4669 	if(posStart > posEnd)
4670 		posStart = posEnd;
4671 
4672 	cmdSelect(posStart, posEnd);
4673 	cmdCharInsert(sDescr.ucs4_str(), sDescr.size());
4674 
4675 	return pAL;
4676 }
4677 
cmdInsertHyperlink(const char * szName,const char * szTitle)4678 UT_Error FV_View::cmdInsertHyperlink(const char * szName, const char * szTitle)
4679 {
4680 	bool bRet;
4681 
4682 	PT_DocPosition posStart = getPoint();
4683 	PT_DocPosition posEnd = posStart;
4684 	PT_DocPosition iPointOrig = posStart;
4685 	PT_DocPosition iAnchorOrig = m_Selection.getSelectionAnchor();
4686 
4687 	if (!isSelectionEmpty())
4688 	{
4689 		if (m_Selection.getSelectionAnchor() < posStart)
4690 		{
4691 			posStart = m_Selection.getSelectionAnchor();
4692 		}
4693 		else
4694 		{
4695 			posEnd = m_Selection.getSelectionAnchor();
4696 		}
4697 
4698 	}
4699 	else
4700 	{
4701 		//No selection
4702 		XAP_Frame * pFrame = static_cast<XAP_Frame *>(getParentData());
4703 		UT_ASSERT((pFrame));
4704 
4705 		pFrame->showMessageBox(AP_STRING_ID_MSG_HyperlinkNoSelection, XAP_Dialog_MessageBox::b_O, XAP_Dialog_MessageBox::a_OK);
4706 		return false;
4707 	}
4708 
4709 	bool relLink = false;
4710 	if (!UT_go_path_is_uri(szName))
4711 		relLink = m_pDoc->isBookmarkRelativeLink(szName);
4712 	// TODO: After strings freeze is lifted, we should
4713 	// TODO: display a message if relLink is true but
4714 	// TODO: szName does not stat.
4715 
4716 	if(!UT_go_path_is_uri(szName) && m_pDoc->isBookmarkUnique(szName) && !relLink)
4717 	{
4718 		//No bookmark of that name in document, tell user.
4719 		XAP_Frame * pFrame = static_cast<XAP_Frame *>(getParentData());
4720 		UT_ASSERT((pFrame));
4721 
4722 		pFrame->showMessageBox(AP_STRING_ID_MSG_HyperlinkNoBookmark,
4723 				       XAP_Dialog_MessageBox::b_O,
4724 				       XAP_Dialog_MessageBox::a_OK,
4725 				       szName);
4726 	}
4727 
4728 	// Hack for bug 2940
4729 	if (posStart == 1) posStart++;
4730 
4731 	// the selection has to be within a single block
4732 	// we could implement hyperlinks spaning arbitrary part of the document
4733 	// but then we could not use <a href=> </a> in the output and
4734 	// I see no obvious need for hyperlinks to span more than a single block
4735 	fl_BlockLayout * pBl1 = _findBlockAtPosition(posStart);
4736 	fl_BlockLayout * pBl2 = _findBlockAtPosition(posEnd);
4737 //
4738 // Handle corner case of selection from outside the left column
4739 //
4740 	if(isInFootnote(posStart))
4741 	{
4742 		if((pBl1 != NULL) && (pBl1->getPosition(true) == posStart))
4743 		{
4744 			if(posEnd > posStart+1)
4745 			{
4746 				posStart++;
4747 			}
4748 		}
4749 	}
4750 	if(isInEndnote(posStart))
4751 	{
4752 		if((pBl1 != NULL) && (pBl1->getPosition(true) == posStart))
4753 		{
4754 			if(posEnd > posStart+1)
4755 			{
4756 				posStart++;
4757 			}
4758 		}
4759 	}
4760 	if(pBl1 != pBl2)
4761 	{
4762 		XAP_Frame * pFrame = static_cast<XAP_Frame *>(getParentData());
4763 		UT_ASSERT((pFrame));
4764 
4765 		pFrame->showMessageBox(AP_STRING_ID_MSG_HyperlinkCrossesBoundaries, XAP_Dialog_MessageBox::b_O, XAP_Dialog_MessageBox::a_OK);
4766 
4767 		return false;
4768 	}
4769 	if(isTOCSelected())
4770 	{
4771 //
4772 // Fixme place message box here
4773 //
4774 		return false;
4775 
4776 	}
4777 	// Silently fail (TODO: pop up message) if we try to nest hyperlinks.
4778 	if (_getHyperlinkInRange(posStart, posEnd) != NULL)
4779 		return false;
4780 //
4781 // Under sum1 induced conditions posEnd could give the same block pointer
4782 // despite being past the end of the block. This extra fail-safe code
4783 // prevents this.
4784 //
4785 	if((pBl1->getPosition() + pBl1->getLength() -1) < posEnd)
4786 	{
4787 		return false;
4788 	}
4789 
4790 	std::string target;
4791 
4792 	if(UT_go_path_is_uri(szName) || relLink)
4793 	{
4794 		target = szName;
4795 	}
4796 	else
4797 	{
4798 		target = "#";
4799 		target += szName;
4800 	}
4801 
4802 	std::string title;
4803 	if (szTitle && *szTitle)
4804 	{
4805 		title = szTitle;
4806 	}
4807 
4808 	const gchar * pAttr[6];
4809 	int attr = 0;
4810 
4811 	pAttr [attr++] = "xlink:href";
4812 	pAttr [attr++] = target.c_str();
4813 	if (szTitle && *szTitle)
4814 	{
4815 		pAttr [attr++] = "xlink:title";
4816 		pAttr [attr++] = title.c_str();
4817 	}
4818 	pAttr[attr++] = 0;
4819 	pAttr[attr++] = 0;
4820 
4821 	UT_DEBUGMSG(("fv_View::cmdInsertHyperlink: target \"%s\"\n", target.c_str()));
4822 
4823 	// Signal PieceTable Change
4824 	_saveAndNotifyPieceTableChange();
4825 
4826 	// we first insert the end run, so that we can use it as a stop
4827 	// after inserting the start run when marking the runs in between
4828 	// as a hyperlink
4829 	bRet = m_pDoc->insertObject(posEnd, PTO_Hyperlink, NULL, NULL);
4830 
4831 	if(bRet)
4832 	{
4833 		const gchar ** pAttrs = pAttr;
4834 		const gchar ** pProps = 0;
4835 		bRet = m_pDoc->insertObject(posStart, PTO_Hyperlink, pAttrs, pProps);
4836 	}
4837 
4838 	if(bRet)
4839 	{
4840 		// because we have inserted two objects around the selection
4841 		// boundaries the original insetion point and selection anchor
4842 		// are now shifted, so we need to fix them
4843 		setPoint(iPointOrig+1);
4844 		m_Selection.setSelectionAnchor(iAnchorOrig + 1);
4845 	}
4846 
4847 	// Signal piceTable is stable again
4848 	_restorePieceTableState();
4849 
4850 	_generalUpdate();
4851 
4852 	return bRet;
4853 
4854 }
4855 
4856 /******************************************************************/
4857 
getCmdInsertRangeVariables(PT_DocPosition & posStart,PT_DocPosition & posEnd,fl_BlockLayout * & pBL1,fl_BlockLayout * & pBL2)4858 void FV_View::getCmdInsertRangeVariables( PT_DocPosition& posStart,
4859 										  PT_DocPosition& posEnd,
4860 										  fl_BlockLayout*& pBL1,
4861 										  fl_BlockLayout*& pBL2 )
4862 {
4863 	posStart = getPoint();
4864 	posEnd = posStart;
4865 
4866 	if (!isSelectionEmpty())
4867 	{
4868 		if (m_Selection.getSelectionAnchor() < posStart)
4869 		{
4870 			posStart = m_Selection.getSelectionAnchor();
4871 		}
4872 		else
4873 		{
4874 			posEnd = m_Selection.getSelectionAnchor();
4875 		}
4876 	}
4877 
4878 	// we cannot bookmark lesser position than 2, because the bookmark object has to be located
4879 	// withing a block; this was the cause of bug 7128
4880 	// (we might consider one day to allow the bookmark object before the first block strux, but the
4881 	// complications this would cause are possibly not worth it)
4882 	if(posStart < 2)
4883 		posStart = 2;
4884 
4885 	posEnd++;
4886 
4887 	pBL1 =_findBlockAtPosition(posStart);
4888 	pBL2 =_findBlockAtPosition(posEnd);
4889 
4890 	//
4891 	// Handle corner case of selection from outside the left column
4892 	//
4893 	if((pBL1!= NULL) && isInFootnote(posStart) && (pBL1->getPosition(true) == posStart))
4894 	{
4895 		if(posEnd > posStart+1)
4896 		{
4897 			posStart++;
4898 		}
4899 	}
4900 	if((pBL1 != NULL) && isInEndnote(posStart) && (pBL1->getPosition(true) == posStart))
4901 	{
4902 		if(posEnd > posStart+1)
4903 		{
4904 			posStart++;
4905 		}
4906 	}
4907 }
4908 
4909 
cmdInsertBookmark(const char * szName)4910 UT_Error FV_View::cmdInsertBookmark(const char * szName)
4911 {
4912 	// Signal PieceTable Change
4913 	_saveAndNotifyPieceTableChange();
4914 	bool bRet;
4915 
4916 	PT_DocPosition posStart = 0, posEnd = 0;
4917 	fl_BlockLayout* pBL1 = 0;
4918 	fl_BlockLayout* pBL2 = 0;
4919 	getCmdInsertRangeVariables( posStart, posEnd, pBL1, pBL2 );
4920 
4921 	if(pBL1 != pBL2)
4922 	{
4923 		//
4924 		// Fixme put message boxes here
4925 		//
4926 		_restorePieceTableState();
4927 		return false;
4928 	}
4929 	if(isTOCSelected())
4930 	{
4931 		//
4932 		// Fixme put message boxes here
4933 		//
4934 		_restorePieceTableState();
4935 		return false;
4936 	}
4937 
4938 	if(!m_pDoc->isBookmarkUnique(static_cast<const gchar*>(szName)))
4939 	{
4940 		XAP_Frame * pFrame = static_cast<XAP_Frame *>(getParentData());
4941 		XAP_Dialog_MessageBox::tAnswer ans = XAP_Dialog_MessageBox::a_NO;
4942 
4943 		if(pFrame)
4944 			ans = pFrame->showMessageBox(AP_STRING_ID_MSG_BookmarkAlreadyExists,
4945 									XAP_Dialog_MessageBox::b_YN, XAP_Dialog_MessageBox::a_NO);
4946 
4947 		if(ans == XAP_Dialog_MessageBox::a_YES)
4948 		{
4949 			//bookmark already exists -- remove it and then reinsert
4950 			UT_DEBUGMSG(("fv_View::cmdInsertBookmark: bookmark \"%s\" exists - removing\n", szName));
4951 			_deleteBookmark(static_cast<const gchar*>(szName), false, &posStart, &posEnd);
4952 		}
4953 		else
4954 		{
4955 			xxx_UT_DEBUGMSG(("User canceled bookmark replacement\n"));
4956 			return false;
4957 		}
4958 	}
4959 
4960 	const gchar* pAttr[6];
4961 
4962 	char name[BOOKMARK_NAME_SIZE + 1];
4963 	strncpy(name, szName, BOOKMARK_NAME_SIZE);
4964 	name[BOOKMARK_NAME_SIZE] = 0;
4965 
4966 	pAttr [0] = "name";
4967 	pAttr [1] = name;
4968 	pAttr [2] = "type";
4969 	pAttr [3] = "start";
4970 	pAttr [4] = 0;
4971 	pAttr [5] = 0;
4972 
4973 	UT_DEBUGMSG(("fv_View::cmdInsertBookmark: szName \"%s\"\n", szName));
4974 
4975 	const gchar ** pProps = 0;
4976 	bRet = m_pDoc->insertObject(posStart, PTO_Bookmark, pAttr, pProps);
4977 
4978 	if(bRet)
4979 	{
4980 		// override the type to mark the end.
4981 		pAttr [3] = "end";
4982 		bRet = m_pDoc->insertObject(posEnd, PTO_Bookmark, pAttr, pProps);
4983 	}
4984 
4985 
4986 	// Signal piceTable is stable again
4987 	_restorePieceTableState();
4988 	_generalUpdate();
4989 
4990 	return bRet;
4991 
4992 }
4993 
4994 UT_Error
cmdInsertXMLID(const std::string & xmlid)4995 FV_View::cmdInsertXMLID( const std::string& xmlid )
4996 {
4997 	UT_DEBUGMSG(("fv_View::cmdInsertXMLID: xmlid:%s\n", xmlid.c_str()));
4998 
4999 	// Signal PieceTable Change
5000 	_saveAndNotifyPieceTableChange();
5001 	UT_Error ret;
5002 
5003 	PT_DocPosition posStart = 0, posEnd = 0;
5004 	fl_BlockLayout* pBL1 = 0;
5005 	fl_BlockLayout* pBL2 = 0;
5006 	getCmdInsertRangeVariables( posStart, posEnd, pBL1, pBL2 );
5007 	UT_DEBUGMSG(("fv_View::cmdInsertXMLID: posStart:%d posEnd:%d\n", posStart, posEnd ));
5008 
5009 	if(pBL1 != pBL2)
5010 	{
5011 		//
5012 		// Fixme put message boxes here
5013 		//
5014 		UT_DEBUGMSG(("fv_View::cmdInsertXMLID: range contains different blocks! xmlid \"%s\"\n", xmlid.c_str()));
5015 		_restorePieceTableState();
5016 		return UT_ERROR;
5017 	}
5018 	if(isTOCSelected())
5019 	{
5020 		//
5021 		// Fixme put message boxes here
5022 		//
5023 		UT_DEBUGMSG(("fv_View::cmdInsertXMLID: can't insert xmlid in TOC! xmlid \"%s\"\n", xmlid.c_str()));
5024 		_restorePieceTableState();
5025 		return UT_ERROR;
5026 	}
5027 
5028 	PD_DocumentRDFHandle rdf = m_pDoc->getDocumentRDF();
5029     std::set< std::string > allIDs;
5030 	rdf->getAllIDs( allIDs );
5031 	if( allIDs.count( xmlid ))
5032 	{
5033 		UT_DEBUGMSG(("fv_View::cmdInsertXMLID: xmlid already in use... %s\n", xmlid.c_str()));
5034 		XAP_Frame * pFrame = static_cast<XAP_Frame *>(getParentData());
5035 		XAP_Dialog_MessageBox::tAnswer ans = XAP_Dialog_MessageBox::a_NO;
5036 
5037 		if(pFrame)
5038 			ans = pFrame->showMessageBox(AP_STRING_ID_MSG_XMLIDAlreadyExists,
5039 										 XAP_Dialog_MessageBox::b_YN, XAP_Dialog_MessageBox::a_NO);
5040 
5041 		if(ans == XAP_Dialog_MessageBox::a_YES)
5042 		{
5043 			// already exists -- remove it and then reinsert
5044 			UT_DEBUGMSG(("fv_View::cmdInsertXMLID: xmlid:%s exists - removing\n", xmlid.c_str()));
5045 			_deleteXMLID( xmlid, false, posStart, posEnd );
5046 		}
5047 		else
5048 		{
5049 			xxx_UT_DEBUGMSG(("User canceled xmlid replacement\n"));
5050 			return UT_OK;
5051 		}
5052 	}
5053 
5054 	const gchar* pa[10] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL };
5055 	pa[0] = PT_XMLID;
5056 	pa[1] = xmlid.c_str();
5057 	// sanity check
5058 	pa[2] = "this-is-an-rdf-anchor";
5059 	pa[3] = "yes";
5060 
5061 	UT_DEBUGMSG(("fv_View::cmdInsertXMLID: inserting xmlid:%s at posStart:%d posEnd:%d\n",
5062 				 xmlid.c_str(), posStart, posEnd ));
5063 
5064 	const gchar ** pAttrs = const_cast<const gchar **>(pa);
5065 	const gchar ** pProps = 0;
5066 	bool bRet = m_pDoc->insertObject(posStart, PTO_RDFAnchor, pAttrs, pProps);
5067 	if(bRet)
5068 	{
5069         pa[4] = PT_RDF_END;
5070         pa[5] = "yes";
5071 		bRet = m_pDoc->insertObject(posEnd, PTO_RDFAnchor, pAttrs, pProps);
5072 	}
5073 
5074 	if( bRet )  ret = UT_OK;
5075 	else   		ret = UT_ERROR;
5076 
5077 	// Signal piceTable is stable again
5078 	_restorePieceTableState();
5079 	_generalUpdate();
5080 
5081 	return ret;
5082 }
5083 
5084 UT_Error
cmdDeleteXMLID(const std::string & xmlid)5085 FV_View::cmdDeleteXMLID( const std::string& xmlid )
5086 {
5087 	return _deleteXMLID( xmlid, true);
5088 }
5089 
5090 
5091 /*****************************************************************/
5092 
5093 
cmdInsertTOC(void)5094 UT_Error FV_View::cmdInsertTOC(void)
5095 {
5096 	// Signal PieceTable Change
5097 	_saveAndNotifyPieceTableChange();
5098 	m_pDoc->beginUserAtomicGlob();
5099 	bool bRet = false; // was not initialised; since ret value is
5100 					   // UT_Error, false should correspond to OK. Tomas
5101 
5102 
5103 	if (!isSelectionEmpty())
5104 	{
5105 		_deleteSelection();
5106 		_generalUpdate();
5107 		fl_BlockLayout * pBL = _findBlockAtPosition(getPoint());
5108 		if(pBL != NULL)
5109 		{
5110 			fl_ContainerLayout * pCL = pBL->myContainingLayout();
5111 			if(pCL->getContainerType() != FL_CONTAINER_DOCSECTION)
5112 			{
5113 				m_pDoc->endUserAtomicGlob();
5114 
5115 				// Signal piceTable is stable again
5116 				_restorePieceTableState();
5117 				_generalUpdate();
5118 				notifyListeners(AV_CHG_MOTION | AV_CHG_ALL);
5119 				return bRet;
5120 			}
5121 		}
5122 		else
5123 		{
5124 			m_pDoc->endUserAtomicGlob();
5125 
5126 			// Signal piceTable is stable again
5127 			_restorePieceTableState();
5128 			_generalUpdate();
5129 			notifyListeners(AV_CHG_MOTION | AV_CHG_ALL);
5130 			return bRet;
5131 		}
5132 	}
5133 //
5134 // Check if there is a hyperlink here
5135 //
5136 	if(getHyperLinkRun(getPoint()) != NULL)
5137 	{
5138 		return false;
5139 	}
5140 	if(!isPointLegal())
5141 	{
5142 	  _charMotion(true,1);
5143 	}
5144 	PT_DocPosition posEnd = 0;
5145 	getEditableBounds(true, posEnd);
5146 	if(getPoint() >= posEnd && !isPointLegal())
5147 	{
5148 	  _charMotion(false,1);
5149 	}
5150 //
5151 // Close off the current block
5152 //
5153 	insertParagraphBreak();
5154 //
5155 // insert just before this block to make the TOC gets inserted just BEFORE
5156 // the Block we just created.
5157 //
5158 // we want this sort of structure in the PT
5159 //
5160 // <Strux Block><Frag><frag><frag><TOC></TOC><Strux Block>|
5161 //                                                        |
5162 // Point is here after insert TOC-------------------------|
5163 //
5164 	fl_BlockLayout * pBL = getCurrentBlock();
5165 	PT_DocPosition pos = pBL->getPosition(true);
5166 	if((pBL->getNext() == NULL) || (pBL->getPrev() == NULL))
5167 	{
5168 		insertParagraphBreak();
5169 		pBL = getCurrentBlock();
5170 		pos = pBL->getPosition(true);
5171 	}
5172 	if(pBL != NULL)
5173 	{
5174 		fl_ContainerLayout * pCL = pBL->myContainingLayout();
5175 		if(pCL->getContainerType() != FL_CONTAINER_DOCSECTION)
5176 		{
5177 				// Signal piceTable is stable again
5178 			_restorePieceTableState();
5179 			_generalUpdate();
5180 			m_pDoc->endUserAtomicGlob();
5181 
5182 			notifyListeners(AV_CHG_MOTION | AV_CHG_ALL);
5183 			return bRet;
5184 		}
5185 	}
5186 	else
5187 	{
5188 
5189 		// Signal piceTable is stable again
5190 		_restorePieceTableState();
5191 		_generalUpdate();
5192 		m_pDoc->endUserAtomicGlob();
5193 		notifyListeners(AV_CHG_MOTION | AV_CHG_ALL);
5194 		return bRet;
5195 	}
5196 	m_pDoc->insertStrux(pos,PTX_SectionTOC);
5197 	pos++;
5198 	m_pDoc->insertStrux(pos,PTX_EndTOC);
5199 	setPoint(pos+1);
5200 	insertParaBreakIfNeededAtPos(getPoint());
5201 	//
5202 	// Now move the point forward until we're in a legal position
5203 	//
5204 	_makePointLegal();
5205 	// Signal piceTable is stable again
5206 	_restorePieceTableState();
5207 	_generalUpdate();
5208 	m_pDoc->endUserAtomicGlob();
5209 	notifyListeners(AV_CHG_MOTION | AV_CHG_ALL);
5210 
5211 	return bRet;
5212 
5213 }
5214 
5215 
5216 /*****************************************************************/
cmdInsertField(const char * szName,const gchar ** extra_attrs,const gchar ** extra_props)5217 UT_Error FV_View::cmdInsertField(const char* szName, const gchar ** extra_attrs, const gchar ** extra_props)
5218 {
5219 	bool bResult = true;
5220 
5221 /*
5222   currently unused
5223   fl_BlockLayout* pBL = _findBlockAtPosition(getPoint());
5224 */
5225 
5226 	// Signal PieceTable Change
5227 	_saveAndNotifyPieceTableChange();
5228 	_insertField(szName,  extra_attrs,extra_props);
5229 
5230 
5231 	// Signal PieceTable Changes have finished
5232 	_restorePieceTableState();
5233 	_generalUpdate();
5234 
5235 	_fixInsertionPointCoords();
5236 	if (!_ensureInsertionPointOnScreen())
5237 	{
5238 //
5239 // Handle End of Paragraph case
5240 //
5241 		PT_DocPosition posEOD;
5242 		getEditableBounds(true, posEOD);
5243 		if(getPoint() == posEOD)
5244 		{
5245 			m_bPointEOL = true;
5246 		}
5247 		_fixInsertionPointCoords();
5248 	}
5249 	return bResult;
5250 }
5251 
cmdInsertGraphic(FG_Graphic * pFG)5252 UT_Error FV_View::cmdInsertGraphic(FG_Graphic* pFG)
5253 {
5254 	bool bDidGlob = false;
5255 
5256 	// Signal PieceTable Change
5257 	_saveAndNotifyPieceTableChange();
5258 
5259 	if (!isSelectionEmpty() && !m_FrameEdit.isActive())
5260 	{
5261 		bDidGlob = true;
5262 		m_pDoc->beginUserAtomicGlob();
5263 		_deleteSelection();
5264 	}
5265 	else if(m_FrameEdit.isActive())
5266 	{
5267 	       m_FrameEdit.setPointInside();
5268 	}
5269 	/*
5270 	  Create a unique identifier for the data item.
5271 	*/
5272 	UT_UUID *uuid = m_pDoc->getNewUUID();
5273 	UT_return_val_if_fail(uuid != NULL, UT_ERROR);
5274 	UT_UTF8String s;
5275 	uuid->toString(s);
5276 	DELETEP(uuid);
5277 
5278 	UT_Error errorCode = _insertGraphic(pFG, s.utf8_str());
5279 	if(m_FrameEdit.isActive())
5280 	{
5281 		m_FrameEdit.setMode(FV_FrameEdit_NOT_ACTIVE);
5282 	}
5283 
5284 	_restorePieceTableState();
5285 
5286 	_generalUpdate();
5287 	if (bDidGlob)
5288 		m_pDoc->endUserAtomicGlob();
5289 	_updateInsertionPoint();
5290 
5291 	return errorCode;
5292 }
5293 
cmdInsertPositionedGraphic(FG_Graphic * pFG)5294 UT_Error FV_View::cmdInsertPositionedGraphic(FG_Graphic* pFG)
5295 {
5296 	fl_BlockLayout * pBlock = NULL;
5297 	fp_Run * pRun = NULL;
5298 	UT_sint32 xCaret, yCaret;
5299 	UT_uint32 heightCaret;
5300 	UT_sint32 xCaret2, yCaret2;
5301 	bool bDirection;
5302 	bool bEOL = false;
5303 	_findPositionCoords(getPoint(), bEOL, xCaret, yCaret, xCaret2, yCaret2, heightCaret, bDirection, &pBlock, &pRun);
5304 	UT_return_val_if_fail(pBlock,UT_ERROR);
5305 	return	cmdInsertPositionedGraphic(pFG,xCaret,yCaret);
5306 
5307 }
5308 
5309 
cmdInsertPositionedGraphic(FG_Graphic * pFG,UT_sint32 mouseX,UT_sint32 mouseY)5310 UT_Error FV_View::cmdInsertPositionedGraphic(FG_Graphic* pFG,UT_sint32 mouseX, UT_sint32 mouseY)
5311 {
5312 	m_pDoc->beginUserAtomicGlob();
5313 
5314 	// Signal PieceTable Change
5315 	_saveAndNotifyPieceTableChange();
5316 
5317 	if (!isSelectionEmpty())
5318 	{
5319 	       _clearSelection();
5320 	}
5321 
5322 	/*
5323 	  Create a unique identifier for the data item.
5324 	*/
5325 	UT_UUID *uuid = m_pDoc->getNewUUID();
5326 	UT_return_val_if_fail(uuid != NULL, UT_ERROR);
5327 	UT_UTF8String s;
5328 	uuid->toString(s);
5329 	//
5330 	// Find a document position close to the requested position
5331 	//
5332 	PT_DocPosition pos = getDocPositionFromXY(mouseX,mouseY);
5333 	fl_BlockLayout * pBlock = getBlockAtPosition(pos);
5334 	fp_Run *  pRun = NULL;
5335 	bool bEOL,bDir;
5336 	bEOL = false;
5337 	UT_sint32 x1,y1,x2,y2,iHeight;
5338 	if(pBlock)
5339 	{
5340 		pRun = pBlock->findPointCoords(pos,bEOL,x1,y1,x2,y2,iHeight,bDir);
5341 	}
5342 	fp_Line * pLine = pRun->getLine();
5343 	if(pLine == NULL)
5344 	{
5345 	        return false;
5346 	}
5347 
5348 	// Also get max width, height
5349 
5350 	fl_DocSectionLayout * pDSL = pBlock->getDocSectionLayout();
5351 	double maxW = static_cast<double>(pDSL->getActualColumnWidth())*0.5/UT_LAYOUT_RESOLUTION;
5352 	double maxH = static_cast<double>(pDSL->getActualColumnHeight())*0.5/ UT_LAYOUT_RESOLUTION;
5353 	//
5354 	// OK calculate all the properties of this image
5355 	//
5356 	UT_String sWidth;
5357 	UT_String sHeight;
5358 	double ratw = 1.0;
5359 	double rath = 1.0;
5360 	double rat = 1.0;
5361 	double dw = static_cast<double>(pFG->getWidth());
5362 	double dh = static_cast<double>(pFG->getHeight());
5363 
5364 	if(dw > maxW/2.)
5365 	{
5366 	     ratw = maxW/dw;
5367 	}
5368 	if(dh > maxH/2.)
5369 	{
5370 	     rath = maxH/dh;
5371 	}
5372 	if(ratw < rath)
5373 	{
5374 	    rat = ratw;
5375 	}
5376 	else
5377 	{
5378 	    rat = rath;
5379 	}
5380 	// This preserves the aspect ratio and limits the size of the images
5381 	dw = dw*rat;
5382 	dh = dh*rat;
5383 	sWidth =  UT_formatDimensionedValue(dw,"in", NULL);
5384 	sHeight =  UT_formatDimensionedValue(dh,"in", NULL);
5385 //
5386 // Create a dataid for the object
5387 //
5388 
5389 	const char * dataID = pFG->createDataItem(m_pDoc,s.utf8_str());
5390 	UT_String sFrameProps;
5391 	UT_String sProp;
5392 	UT_String sVal;
5393 	sProp = "frame-type";
5394 	sVal = "image";
5395 	UT_String_setProperty(sFrameProps,sProp,sVal);
5396 //
5397 // Turn off the borders.
5398 //
5399 	sProp = "top-style";
5400 	sVal = "none";
5401 	UT_String_setProperty(sFrameProps,sProp,sVal);
5402 	sProp = "right-style";
5403 	UT_String_setProperty(sFrameProps,sProp,sVal);
5404 	sProp = "left-style";
5405 	UT_String_setProperty(sFrameProps,sProp,sVal);
5406 	sProp = "bot-style";
5407 	UT_String_setProperty(sFrameProps,sProp,sVal);
5408 //
5409 // Set width/Height
5410 //
5411 	sProp = "frame-width";
5412 	sVal = sWidth;
5413 	UT_String_setProperty(sFrameProps,sProp,sVal);
5414 	sProp = "frame-height";
5415 	sVal = sHeight;
5416 	UT_String_setProperty(sFrameProps,sProp,sVal);
5417 	double xpos = 0.0;
5418 	double ypos= 0.0;
5419 
5420 	sProp = "position-to";
5421 	sVal = "column-above-text";
5422 	UT_String_setProperty(sFrameProps,sProp,sVal);
5423 	if(isInHdrFtr(pos))
5424 	{
5425 		clearHdrFtrEdit();
5426 		warpInsPtToXY(0,0,false);
5427 		pos = getPoint();
5428 	}
5429 
5430 //
5431 // Now calculate the Y offset to the Column
5432 //
5433 	fp_Column * pCol = static_cast<fp_Column *>(pLine->getColumn());
5434 	UT_sint32 ixoff,iyoff;
5435 	fp_Page * pPage = pCol->getPage();
5436 	pPage->getScreenOffsets(static_cast<fp_Container *>(pCol),ixoff,iyoff);
5437 	iHeight = static_cast<UT_sint32>(dh*UT_LAYOUT_RESOLUTION);
5438 	UT_sint32 iposy = mouseY - iyoff - iHeight/2;
5439 	ypos = static_cast<double>(iposy)/static_cast<double>(UT_LAYOUT_RESOLUTION);
5440 	sProp = "frame-col-ypos";
5441 	sVal = UT_formatDimensionedValue(ypos,"in", NULL);
5442 	UT_String_setProperty(sFrameProps,sProp,sVal);
5443 	sProp = "wrap-mode";
5444 	sVal = "wrapped-both";
5445 	UT_String_setProperty(sFrameProps,sProp,sVal);
5446         UT_sint32 iWidth = static_cast<UT_sint32>(dw*UT_LAYOUT_RESOLUTION);
5447 	UT_sint32 iposx = mouseX - ixoff - iWidth/2;
5448 	UT_sint32 iColW = static_cast<UT_sint32>(maxW*2.*UT_LAYOUT_RESOLUTION);
5449 	if((iposx + iWidth) > (pCol->getX() + iColW))
5450 	{
5451 	  iposx = iColW - iWidth - pCol->getX();
5452 	}
5453 	if(iposx < pCol->getX())
5454 	{
5455 	      iposx = 0;
5456 	}
5457 
5458 	UT_DEBUGMSG(("iposx %d pCol->getX() %d \n",iposx,pCol->getX()));
5459 	xpos =  static_cast<double>(iposx)/static_cast<double>(UT_LAYOUT_RESOLUTION);
5460 
5461         sProp = "frame-col-xpos";
5462         sVal = UT_formatDimensionedValue(xpos,"in", NULL);
5463         UT_DEBUGMSG((" %s %s \n",sProp.c_str(),sVal.c_str()));
5464 	UT_String_setProperty(sFrameProps,sProp,sVal);
5465 //
5466 // Wrapped Mode
5467 //
5468 	sProp = "wrap-mode";
5469 	sVal = "wrapped-both";
5470 	UT_String_setProperty(sFrameProps,sProp,sVal);
5471 //
5472 // Now define the Frame attributes strux
5473 //
5474 	const gchar * attributes[5] = {PT_STRUX_IMAGE_DATAID,
5475 					  NULL,"props",NULL,NULL};
5476 	attributes[1] = dataID;
5477 	attributes[3] = sFrameProps.c_str();
5478 //
5479 // This should place the the frame strux immediately after the block containing
5480 // position posXY.
5481 // It returns the Frag_Strux of the new frame.
5482 //
5483 	fl_BlockLayout * pBL = pBlock;
5484 	if((pBL == NULL) || (pRun == NULL))
5485 	{
5486 	  return UT_ERROR;
5487 	}
5488 	fl_BlockLayout * pPrevBL = pBL;
5489 	while(pBL && ((pBL->myContainingLayout()->getContainerType() == FL_CONTAINER_ENDNOTE) || (pBL->myContainingLayout()->getContainerType() == FL_CONTAINER_FOOTNOTE) || (pBL->myContainingLayout()->getContainerType() == FL_CONTAINER_TOC)|| (pBL->myContainingLayout()->getContainerType() == FL_CONTAINER_FRAME)))
5490 	{
5491         UT_DEBUGMSG(("Skipping Block %p \n",pBL));
5492 		pPrevBL = pBL;
5493 		pBL = pBL->getPrevBlockInDocument();
5494 	}
5495 	if(pBL == NULL)
5496 	{
5497 	        pBL = pPrevBL;
5498 	}
5499 	UT_ASSERT((pBL->myContainingLayout()->getContainerType() != FL_CONTAINER_HDRFTR)
5500 		  && (pBL->myContainingLayout()->getContainerType() != FL_CONTAINER_SHADOW));
5501 	pos = pBL->getPosition();
5502 	pf_Frag_Strux * pfFrame = NULL;
5503 	m_pDoc->insertStrux(pos,PTX_SectionFrame,attributes,NULL,&pfFrame);
5504 	PT_DocPosition posFrame = pfFrame->getPos();
5505 	m_pDoc->insertStrux(posFrame+1,PTX_EndFrame);
5506 	insertParaBreakIfNeededAtPos(posFrame+2);
5507 
5508 	// Signal PieceTable Changes have finished
5509 	_restorePieceTableState();
5510 	m_pDoc->endUserAtomicGlob();
5511 	_generalUpdate();
5512 	if(!isPointLegal())
5513 	{
5514 	      _makePointLegal();
5515 	}
5516 	_ensureInsertionPointOnScreen();
5517 	notifyListeners(AV_CHG_MOTION | AV_CHG_ALL);
5518 	return UT_OK;
5519 }
5520 
5521 /*!
5522  * This method inserts a MathML object and it's Latex representation
5523  * at the current insertion point.
5524  * It leaves the Object selected so it can be altered as needed.
5525  */
cmdInsertLatexMath(UT_UTF8String & sLatex,UT_UTF8String & sMath)5526 bool FV_View::cmdInsertLatexMath(UT_UTF8String & sLatex,
5527 						   UT_UTF8String & sMath)
5528 {
5529   //
5530   // First create the Data Items
5531   //
5532         UT_UTF8String sMathName;
5533         UT_UTF8String sLatexName;
5534         sMathName = "MathLatex";
5535 	sLatexName = "LatexMath";
5536 	/*
5537 	  Create a unique identifier for the data item.
5538 	*/
5539 	UT_UUID *uuid = m_pDoc->getNewUUID();
5540 	UT_return_val_if_fail(uuid != NULL, false);
5541 	UT_UTF8String s;
5542 	uuid->toString(s);
5543 	sMathName += s;
5544 	sLatexName += s;
5545 	delete uuid;
5546 	UT_DEBUGMSG(("Inserting latex id name %s \n",sLatexName.utf8_str()));
5547 	//
5548 	// Insert these into the Piece Table
5549 	//
5550 	UT_ByteBuf mathBuf;
5551 	UT_ByteBuf latexBuf;
5552 	mathBuf.ins(0,reinterpret_cast<const UT_Byte *>(sMath.utf8_str()),static_cast<UT_uint32>(sMath.size()));
5553 	latexBuf.ins(0,reinterpret_cast<const UT_Byte *>(sLatex.utf8_str()),static_cast<UT_uint32>(sLatex.size()));
5554 	m_pDoc->createDataItem(sMathName.utf8_str(),false,&mathBuf,"",NULL);
5555 	m_pDoc->createDataItem(sLatexName.utf8_str(),false,&latexBuf,"",NULL);
5556 	// OK Insert the MathML Object
5557 	const gchar * atts[9]={"dataid",NULL,"latexid",NULL,"props",NULL,NULL,NULL,NULL};
5558 	atts[1] = static_cast<const gchar *>(sMathName.utf8_str());
5559 	atts[3] = static_cast<const gchar *>(sLatexName.utf8_str());
5560 	const gchar *cur_style = NULL;
5561 	getStyle(&cur_style);
5562 	if((cur_style != NULL) && (*cur_style) && (strcmp(cur_style,"None") != 0))
5563 	{
5564 		atts[6] = PT_STYLE_ATTRIBUTE_NAME;
5565 		atts[7] = cur_style;
5566 	}
5567 
5568 	bool bDidGlob = false;
5569 	const gchar ** props = NULL;
5570 
5571 	// Signal PieceTable Change
5572 	_saveAndNotifyPieceTableChange();
5573 	PT_DocPosition pos = getPoint();
5574 	if (!isSelectionEmpty())
5575 	{
5576 	        getCharFormat(&props,false,pos);
5577 		bDidGlob = true;
5578 		m_pDoc->beginUserAtomicGlob();
5579 		_deleteSelection();
5580 	}
5581 	else
5582 	{
5583 	        getCharFormat(&props,false,pos);
5584 	}
5585 	pos = getPoint();
5586 	UT_UTF8String sNewProps;
5587 	UT_UTF8String sProp;
5588 	UT_UTF8String sVal;
5589 	UT_sint32 i = 0;
5590 	if(props)
5591 	{
5592 	  while(props[i] != NULL)
5593 	  {
5594 	    sProp = props[i];
5595 	    sVal = props[i+1];
5596 	    UT_UTF8String_setProperty(sNewProps,sProp,sVal);
5597 	    i +=2;
5598 	  }
5599 	  g_free(props);
5600 	}
5601 	atts[5] = sNewProps.utf8_str();
5602 	m_pDoc->insertObject(pos,PTO_Math,atts,NULL);
5603 
5604 	if (bDidGlob)
5605 		m_pDoc->endUserAtomicGlob();
5606 
5607 	_generalUpdate();
5608 	_restorePieceTableState();
5609 	cmdSelect(pos,pos+1);
5610 	return true;
5611 }
5612 
5613 /*!
5614  * This method inserts a MathML object at the point presented.
5615  * It assumes that a data item with a name of the supplied filename has
5616  * already been inserted.
5617  */
cmdInsertMathML(const char * szUID,PT_DocPosition pos)5618 bool FV_View::cmdInsertMathML(const char * szUID,PT_DocPosition pos)
5619 {
5620 	UT_DebugOnly<PT_DocPosition> posDebug = pos;
5621 	UT_DEBUGMSG(("Insert Math Object at %d name %s \n",(PT_DocPosition)posDebug,szUID));
5622 	const gchar * atts[5]={"dataid",NULL,NULL,NULL,NULL};
5623 	atts[1] = szUID;
5624 	const gchar *cur_style = NULL;
5625 	getStyle(&cur_style);
5626 	if((cur_style != NULL) && (*cur_style) && (strcmp(cur_style,"None") != 0))
5627 	{
5628 		atts[2] = PT_STYLE_ATTRIBUTE_NAME;
5629 		atts[3] = cur_style;
5630 	}
5631 	bool bDidGlob = false;
5632 	const gchar ** props = NULL;
5633 
5634 	// Signal PieceTable Change
5635 	_saveAndNotifyPieceTableChange();
5636 
5637 	if (!isSelectionEmpty())
5638 	{
5639 		bDidGlob = true;
5640 		m_pDoc->beginUserAtomicGlob();
5641 		_deleteSelection();
5642 	}
5643 	_makePointLegal();
5644 	getCharFormat(&props,false,getPoint());
5645 	m_pDoc->insertObject(getPoint(),PTO_Math,atts,props);
5646 
5647 	if (bDidGlob)
5648 		m_pDoc->endUserAtomicGlob();
5649 
5650 	_generalUpdate();
5651 
5652 	_restorePieceTableState();
5653 	_updateInsertionPoint();
5654 	return true;
5655 }
5656 
5657 
5658 /*!
5659  * This method inserts a Embed object at the point presented.
5660  * The calling routine should pass in a pointer to bytebuf that represents the
5661  * object.
5662  * Also needed are strings for the Mime-type and the type of Embeded object.
5663  *
5664  * eg for a GNOME-Office chart we'll have MIME-TYPE "application/chart+xml"
5665  * and sProps="embed-type: GOChart";
5666  */
cmdInsertEmbed(const UT_ByteBuf * pBuf,PT_DocPosition pos,const char * szMime,const char * szProps)5667 bool FV_View::cmdInsertEmbed(const UT_ByteBuf * pBuf,PT_DocPosition pos,const char * szMime,const char * szProps)
5668 {
5669 
5670 	const gchar * atts[7]={"dataid",NULL,"props",NULL,NULL,NULL,NULL};
5671 	UT_UTF8String sUID="obj-", s;
5672 	UT_UUID *uuid = m_pDoc->getNewUUID();
5673 	UT_return_val_if_fail(uuid != NULL, false);
5674 	uuid->toString(s);
5675 	sUID += s;
5676 	atts[1] = sUID.utf8_str();
5677 	const gchar *cur_style = NULL;
5678 	UT_String sBuf(reinterpret_cast<const char *>(pBuf->getPointer(0)),pBuf->getLength());
5679 	UT_DEBUGMSG(("Chart text is... \n %s \n",sBuf.c_str()));
5680 	bool result = m_pDoc->createDataItem(sUID.utf8_str(),false,pBuf, szMime, NULL);
5681 	if(!result)
5682 	{
5683 	    return result;
5684 	}
5685 	getStyle(&cur_style);
5686 	if((cur_style != NULL) && (*cur_style) && (strcmp(cur_style,"None") != 0))
5687 	{
5688 		atts[4] = PT_STYLE_ATTRIBUTE_NAME;
5689 		atts[5] = cur_style;
5690 	}
5691 	bool bDidGlob = false;
5692 	const gchar ** props = NULL;
5693 
5694 	// Signal PieceTable Change
5695 	_saveAndNotifyPieceTableChange();
5696 
5697 	if (!isSelectionEmpty())
5698 	{
5699 		bDidGlob = true;
5700 		m_pDoc->beginUserAtomicGlob();
5701 		_deleteSelection();
5702 		// Reevaluate pos after deleting the selection
5703 		pos = getPoint();
5704 	}
5705 	getCharFormat(&props,false,pos);
5706 	UT_UTF8String sFullProps;
5707 	UT_UTF8String sProp,sVal;
5708 	UT_UTF8String sProps;
5709 	UT_sint32 i = 0;
5710 	if(props)
5711 	{
5712 	  for(i=0;props[i] != NULL;i+=2)
5713 	  {
5714 	    sProp = props[i];
5715 	    sVal = props[i+1];
5716 	    UT_UTF8String_setProperty(sFullProps,sProp,sVal);
5717 	  }
5718 	  g_free(props);
5719 	}
5720 	sProps = szProps;
5721 	UT_DEBUGMSG(("Supplied props %s \n",sProps.utf8_str()));
5722 	UT_UTF8String_addPropertyString(sFullProps,sProps);
5723 	UT_DEBUGMSG(("Property String at Update Object is %s \n",sFullProps.utf8_str()));
5724 	atts[3]=sFullProps.utf8_str();
5725 	m_pDoc->insertObject(pos,PTO_Embed,atts,NULL);
5726 	if (bDidGlob)
5727 		m_pDoc->endUserAtomicGlob();
5728 
5729 	_generalUpdate();
5730 
5731 	_restorePieceTableState();
5732 	_updateInsertionPoint();
5733 	cmdSelect(pos,pos+1);
5734 	return true;
5735 }
5736 
5737 /*!
5738  * This method updates the Embedded object currently selected with a new
5739  * object defined with the supplied bytebuffer, as well as strings to represent
5740  * the MIME/Type and Object type.
5741  *
5742  * eg for a GNOME-Office chart we'll have MIME-TYPE "application/chart+xml"
5743  * and sProps="embed-type: GOChart";
5744  */
cmdUpdateEmbed(const UT_ByteBuf * pBuf,const char * szMime,const char * szProps)5745 bool FV_View::cmdUpdateEmbed(const UT_ByteBuf * pBuf, const char * szMime, const char * szProps)
5746 {
5747 	if (isSelectionEmpty())
5748 	{
5749 	     return false;
5750 	}
5751 	PT_DocPosition pos1 = getPoint();
5752 	PT_DocPosition pos2 = getSelectionAnchor();
5753 	PT_DocPosition posTemp = 0;
5754 	if(pos2 < pos1)
5755 	{
5756 	  posTemp = pos2;
5757 	  pos2 = pos1;
5758 	  pos1 = posTemp;
5759 	}
5760 	fl_BlockLayout * pBL =	getCurrentBlock();
5761 	if(!pBL)
5762 		return false;
5763 	fp_Run * pRun;
5764 	UT_sint32 xPoint,yPoint,xPoint2,yPoint2,iPointHeight;
5765 	bool bDirection;
5766 	pRun = pBL->findPointCoords(pos1, false, xPoint,
5767 								yPoint, xPoint2, yPoint2,
5768 								iPointHeight, bDirection);
5769 	if(pRun && (pRun->getType() != FPRUN_EMBED) )
5770 	{
5771 	  pos1 = pos2;
5772 	}
5773 	pRun = pBL->findPointCoords(pos1, false, xPoint,
5774 								yPoint, xPoint2, yPoint2,
5775 								iPointHeight, bDirection);
5776 	if(pRun == NULL)
5777 	{
5778 	  return false;
5779 	}
5780 	if(pRun->getType() != FPRUN_EMBED)
5781 	{
5782 	  return false;
5783 	}
5784 	const gchar * atts[7]={"dataid",NULL,"props",NULL,NULL,NULL,NULL};
5785 	UT_UTF8String sUID="obj-", s;
5786 	UT_UUID *uuid = m_pDoc->getNewUUID();
5787 	UT_return_val_if_fail(uuid != NULL, false);
5788 	uuid->toString(s);
5789 	sUID += s;
5790 	atts[1] = sUID.utf8_str();
5791 	bool bres = m_pDoc->createDataItem(sUID.utf8_str(),false,pBuf, szMime, NULL);
5792 	UT_return_val_if_fail(bres,false)
5793 	const gchar *cur_style = NULL;
5794 	getStyle(&cur_style);
5795 	if((cur_style != NULL) && (*cur_style) && (strcmp(cur_style,"None") != 0))
5796 	{
5797 		atts[4] = PT_STYLE_ATTRIBUTE_NAME;
5798 		atts[5] = cur_style;
5799 	}
5800 	const gchar ** props = NULL;
5801 
5802 	// Signal PieceTable Change
5803 	_saveAndNotifyPieceTableChange();
5804 	m_pDoc->beginUserAtomicGlob();
5805 	getCharFormat(&props,false,pos1);
5806 	UT_UTF8String sFullProps;
5807 	UT_UTF8String sProp,sVal;
5808 	UT_UTF8String sProps;
5809 	sProps = szProps;
5810 	UT_sint32 i = 0;
5811 	if(props)
5812 	{
5813 	  for(i=0;props[i] != NULL;i+=2)
5814 	  {
5815 	    sProp = props[i];
5816 	    sVal = props[i+1];
5817 	    UT_DEBUGMSG(("Update Embed Prop %s val %s \n",props[i],props[i+1]));
5818 	    UT_UTF8String_setProperty(sFullProps,sProp,sVal);
5819 	  }
5820 	  g_free(props);
5821 	}
5822 	UT_DEBUGMSG(("Supplied props %s \n",sProps.utf8_str()));
5823 	UT_UTF8String_addPropertyString(sFullProps,sProps);
5824 	atts[3]=sFullProps.utf8_str();
5825 	UT_DEBUGMSG(("Property String at Update Object is %s \n",atts[3]));
5826 	_deleteSelection();
5827 	m_pDoc->insertObject(pos1,PTO_Embed,atts,NULL);
5828 	m_pDoc->endUserAtomicGlob();
5829 
5830 	_generalUpdate();
5831 	_restorePieceTableState();
5832 	_updateInsertionPoint();
5833 	cmdSelect(pos1,pos1+1);
5834 	return true;
5835 }
5836 
5837 /*!
5838  * This method updates the Embedded object in pRun with a new
5839  * object defined with the supplied bytebuffer, as well as strings to represent
5840  * the MIME/Type and Object type.
5841  *
5842  * eg for a GNOME-Office chart we'll have MIME-TYPE "application/chart+xml"
5843  * and sProps="embed-type: GOChart";
5844  */
cmdUpdateEmbed(fp_Run * pRun,const UT_ByteBuf * pBuf,const char * szMime,const char * szProps)5845 bool FV_View::cmdUpdateEmbed(fp_Run * pRun, const UT_ByteBuf * pBuf, const char * szMime, const char * szProps)
5846 {
5847 	if(pRun == NULL || pRun->getType() != FPRUN_EMBED)
5848 	{
5849 	  return false;
5850 	}
5851 	PT_DocPosition pos;
5852 	bool flag;
5853 	pRun->mapXYToPosition(0, 0, pos, flag, flag, flag);
5854 	cmdSelect (pos, pos+1);
5855 	const gchar * atts[7]={"dataid",NULL,"props",NULL,NULL,NULL,NULL};
5856 	UT_UTF8String sUID="obj-", s;
5857 	UT_UUID *uuid = m_pDoc->getNewUUID();
5858 	UT_return_val_if_fail(uuid != NULL, false);
5859 	uuid->toString(s);
5860 	sUID += s;
5861 	atts[1] = sUID.utf8_str();
5862 	bool bres = m_pDoc->createDataItem(sUID.utf8_str(),false,pBuf, szMime, NULL);
5863 	UT_return_val_if_fail(bres,false)
5864 	const gchar *cur_style = NULL;
5865 	getStyle(&cur_style);
5866 	if((cur_style != NULL) && (*cur_style) && (strcmp(cur_style,"None") != 0))
5867 	{
5868 		atts[4] = PT_STYLE_ATTRIBUTE_NAME;
5869 		atts[5] = cur_style;
5870 	}
5871 	const gchar ** props = NULL;
5872 
5873 	// Signal PieceTable Change
5874 	_saveAndNotifyPieceTableChange();
5875 	m_pDoc->beginUserAtomicGlob();
5876 	getCharFormat(&props,false,pos);
5877 	UT_UTF8String sFullProps;
5878 	UT_UTF8String sProp,sVal;
5879 	UT_UTF8String sProps;
5880 	sProps = szProps;
5881 	UT_sint32 i = 0;
5882 	if(props)
5883 	{
5884 	  for(i=0;props[i] != NULL;i+=2)
5885 	  {
5886 	    sProp = props[i];
5887 		// Filter out size properties
5888 		if (sProp == "width" || sProp == "height" || sProp == "descent"
5889 			|| sProp == "ascent")
5890 			sVal=NULL;
5891 		else
5892 	    	sVal = props[i+1];
5893 	    UT_DEBUGMSG(("Update Embed Prop %s val %s \n",props[i],props[i+1]));
5894 	    UT_UTF8String_setProperty(sFullProps,sProp,sVal);
5895 	  }
5896 	  g_free(props);
5897 	}
5898 	UT_DEBUGMSG(("Supplied props %s \n",sProps.utf8_str()));
5899 	UT_UTF8String_addPropertyString(sFullProps,sProps);
5900 	atts[3]=sFullProps.utf8_str();
5901 	UT_DEBUGMSG(("Property String at Update Object is %s \n",atts[3]));
5902 	m_pDoc->changeSpanFmt(PTC_AddFmt, pos, pos+1, atts, NULL);
5903 	m_pDoc->endUserAtomicGlob();
5904 
5905 	_generalUpdate();
5906 	_restorePieceTableState();
5907 	_updateInsertionPoint();
5908 	cmdSelect(pos,pos+1);
5909 	return true;
5910 }
5911 
5912 /*!
5913  * This method deletes the Embedded object in pRun.
5914  */
cmdDeleteEmbed(fp_Run * pRun)5915 bool FV_View::cmdDeleteEmbed(fp_Run * pRun)
5916 {
5917 	if(pRun == NULL || pRun->getType() != FPRUN_EMBED)
5918 	{
5919 	  return false;
5920 	}
5921 	PT_DocPosition pos;
5922 	bool flag;
5923 	pRun->mapXYToPosition(0, 0, pos, flag, flag, flag);
5924 	cmdSelect (pos, pos+1);
5925 	_saveAndNotifyPieceTableChange();
5926 	m_pDoc->beginUserAtomicGlob();
5927 	_deleteSelection();
5928 	m_pDoc->endUserAtomicGlob();
5929 
5930 	_generalUpdate();
5931 	_restorePieceTableState();
5932 	_updateInsertionPoint();
5933 	cmdSelect(pos,pos);
5934 	return true;
5935 }
5936 
5937 /*!
5938  * This method inserts an image at the strux of type iStruxType at the
5939  * point given by ipos.
5940  * This is useful for speficifying images as backgrounds to pages and cells.
5941  */
cmdInsertGraphicAtStrux(FG_Graphic * pFG,PT_DocPosition iPos,PTStruxType iStruxType)5942 UT_Error FV_View::cmdInsertGraphicAtStrux(FG_Graphic* pFG, PT_DocPosition iPos, PTStruxType iStruxType)
5943 {
5944 	bool bDidGlob = false;
5945 
5946 	// Signal PieceTable Change
5947 	_saveAndNotifyPieceTableChange();
5948 
5949 	/*
5950 	  Create a unique identifier for the data item.
5951 	*/
5952 	UT_UUID *uuid = m_pDoc->getNewUUID();
5953 	UT_return_val_if_fail(uuid != NULL, UT_ERROR);
5954 	UT_UTF8String s;
5955 	uuid->toString(s);
5956 
5957 	UT_Error errorCode = pFG->insertAtStrux(m_pDoc,
5958 											m_pG->getDeviceResolution(),
5959 											iPos,
5960 											iStruxType, s.utf8_str());
5961 
5962 	_restorePieceTableState();
5963 
5964 	_generalUpdate();
5965 	if (bDidGlob)
5966 		m_pDoc->endUserAtomicGlob();
5967 	_updateInsertionPoint();
5968 
5969 	return errorCode;
5970 }
5971 
5972 #ifdef ENABLE_SPELL
cmdContextSuggest(UT_uint32 ndx,fl_BlockLayout * ppBL,const fl_PartOfBlockPtr & ppPOB)5973 void FV_View::cmdContextSuggest(UT_uint32 ndx, fl_BlockLayout * ppBL,
5974 								const fl_PartOfBlockPtr& ppPOB)
5975 {
5976 	// locate the squiggle
5977 	PT_DocPosition pos = getPoint();
5978 	fl_BlockLayout* pBL;
5979 	fl_PartOfBlockPtr pPOB;
5980 
5981 	if (!ppBL)
5982 		pBL = _findBlockAtPosition(pos);
5983 	else
5984 		pBL = ppBL;
5985 	UT_ASSERT(pBL);
5986 
5987 	if (!ppPOB)
5988 		pPOB = pBL->getSpellSquiggles()->get(pos - pBL->getPosition());
5989 	else
5990 		pPOB = ppPOB;
5991 	UT_ASSERT(pPOB);
5992 
5993 	// grab the suggestion
5994 	UT_UCSChar * replace = _lookupSuggestion(pBL, pPOB, ndx);
5995 
5996 	if (!replace)
5997 		return;
5998 
5999 	// make the change
6000 	UT_ASSERT(isSelectionEmpty());
6001 
6002 	moveInsPtTo(static_cast<PT_DocPosition>(pBL->getPosition() + pPOB->getOffset()));
6003 	extSelHorizontal(true, pPOB->getPTLength());
6004 
6005 	UT_UCSChar * selection;
6006 	getSelectionText(selection);
6007 	getDictForSelection ()->correctWord (selection, UT_UCS4_strlen (selection),
6008 										 replace, UT_UCS4_strlen (replace));
6009 	cmdCharInsert(replace, UT_UCS4_strlen(replace));
6010 	FREEP(selection);
6011 	FREEP(replace);
6012 }
6013 
cmdContextIgnoreAll(void)6014 void FV_View::cmdContextIgnoreAll(void)
6015 {
6016 	// locate the squiggle
6017 	PT_DocPosition pos = getPoint();
6018 	fl_BlockLayout* pBL = _findBlockAtPosition(pos);
6019 	UT_return_if_fail(pBL);
6020 	const fl_PartOfBlockPtr& pPOB = pBL->getSpellSquiggles()->get(pos - pBL->getPosition());
6021 	if(!pPOB) // this can happen with very rapid right-clicks
6022 	{
6023 		return;
6024 	}
6025 
6026 	// grab a copy of the word
6027 	UT_GrowBuf pgb(1024);
6028 	bool bRes = pBL->getBlockBuf(&pgb);
6029 	UT_ASSERT(bRes);
6030 	if(!bRes)
6031 	{
6032 		UT_WARNINGMSG(("getBlockBuf() failed in %s:%d",
6033 					   __FILE__, __LINE__));
6034 	}
6035 
6036 	const UT_UCSChar * pBuf;
6037 	UT_sint32 iLength, iPTLength, iBlockPos;
6038 
6039 	fl_BlockSpellIterator BSI(pBL, pPOB->getOffset());
6040 	BSI.nextWordForSpellChecking(pBuf, iLength, iBlockPos, iPTLength);
6041 
6042 	// make the change
6043 	getDictForSelection ()->ignoreWord ((const UT_UCSChar *)pBuf, (size_t)iLength);
6044 	{
6045 		// remove the squiggles, too
6046 		fl_DocSectionLayout * pSL = m_pLayout->getFirstSection();
6047 		if(pSL)
6048 		{
6049 			fl_BlockLayout* b = pSL->getNextBlockInDocument();
6050 			while (b)
6051 			{
6052 				// TODO: just check and remove matching squiggles
6053 				// for now, destructively recheck the whole thing
6054 				m_pLayout->queueBlockForBackgroundCheck(FL_DocLayout::bgcrSpelling, b);
6055 				b = static_cast<fl_BlockLayout *>(b->getNextBlockInDocument());
6056 			}
6057 		}
6058 	}
6059 }
6060 
cmdContextAdd(void)6061 void FV_View::cmdContextAdd(void)
6062 {
6063 	// locate the squiggle
6064 	PT_DocPosition pos = getPoint();
6065 	fl_BlockLayout* pBL = _findBlockAtPosition(pos);
6066 	UT_return_if_fail(pBL);
6067 	const fl_PartOfBlockPtr& pPOB = pBL->getSpellSquiggles()->get(pos - pBL->getPosition());
6068 	if(!pPOB) // this can happen with very rapid right-clicks
6069 	{
6070 		return;
6071 	}
6072 
6073 	// grab a copy of the word
6074 	UT_GrowBuf pgb(1024);
6075 	bool bRes = pBL->getBlockBuf(&pgb);
6076 	UT_ASSERT(bRes);
6077 	if(!bRes)
6078 	{
6079 		UT_WARNINGMSG(("getBlockBuf() failed in %s:%d",
6080 					   __FILE__, __LINE__));
6081 	}
6082 
6083 	const UT_UCSChar * pBuf;
6084 	UT_sint32 iLength, iPTLength, iBlockPos;
6085 
6086 	fl_BlockSpellIterator BSI(pBL, pPOB->getOffset());
6087 	BSI.nextWordForSpellChecking(pBuf, iLength, iBlockPos, iPTLength);
6088 
6089 	// make the change
6090 	if (getDictForSelection ()->addToCustomDict (pBuf, iLength))
6091 	{
6092 		// remove the squiggles, too
6093 		fl_DocSectionLayout * pSL = m_pLayout->getFirstSection();
6094 		if(pSL)
6095 		{
6096 			fl_BlockLayout* b = pSL->getNextBlockInDocument();
6097 			while (b)
6098 			{
6099 				// TODO: just check and remove matching squiggles
6100 				// for now, destructively recheck the whole thing
6101 				if(b->getContainerType() == FL_CONTAINER_BLOCK)
6102 				{
6103 					m_pLayout->queueBlockForBackgroundCheck(FL_DocLayout::bgcrSpelling, b);
6104 					b = static_cast<fl_BlockLayout *>(b->getNextBlockInDocument());
6105 				}
6106 				else
6107 				{
6108 					b = static_cast<fl_BlockLayout *>(b->getNext());
6109 				}
6110 			}
6111 		}
6112 	}
6113 }
6114 #endif
6115 
6116 
6117 /*!
6118  * Remove all the Headers or footers from the section owning the current Page.
6119 \param bool isHeader remove the header if true, the footer if false.
6120 */
cmdRemoveHdrFtr(bool isHeader)6121 void FV_View::cmdRemoveHdrFtr( bool isHeader)
6122 {
6123 //
6124 // Branch to Header/Footer sections.
6125 //
6126 	fp_ShadowContainer * pHFCon = NULL;
6127 	fl_HdrFtrShadow * pShadow = NULL;
6128 	fl_HdrFtrSectionLayout * pHdrFtr = NULL;
6129 
6130 	if(isHeader)
6131 	{
6132 		fp_Page * pPage = getCurrentPage();
6133 		pHFCon = pPage->getHdrFtrP(FL_HDRFTR_HEADER);
6134 		if(pHFCon == NULL)
6135 		{
6136 			return;
6137 		}
6138 //
6139 // Now see if we are in the header to be removed. If so, jump out.
6140 //
6141 		if (!isSelectionEmpty())
6142 			_clearSelection();
6143 		if(isHdrFtrEdit())
6144 		{
6145 			clearHdrFtrEdit();
6146 			_setPoint(pPage->getFirstLastPos(true));
6147 		}
6148 	}
6149 	else
6150 	{
6151 		fp_Page * pPage = getCurrentPage();
6152 		pHFCon = pPage->getHdrFtrP(FL_HDRFTR_FOOTER);
6153 		if(pHFCon == NULL)
6154 		{
6155 			return;
6156 		}
6157 //
6158 // Now see if we are in the Footer to be removed. If so, jump out.
6159 //
6160 		if (!isSelectionEmpty())
6161 			_clearSelection();
6162 		if(isHdrFtrEdit())
6163 		{
6164 			clearHdrFtrEdit();
6165 			_setPoint(pPage->getFirstLastPos(false));
6166 		}
6167 	}
6168 	pShadow = pHFCon->getShadow();
6169 	UT_return_if_fail(pShadow);
6170 
6171 	m_pDoc->beginUserAtomicGlob();
6172 
6173 	_saveAndNotifyPieceTableChange();
6174 //
6175 // Save current document position.
6176 //
6177 	PT_DocPosition curPoint = getPoint();
6178 //
6179 // Get the hdrftrSectionLayout
6180 // Get it's position.
6181 // Find the last run in the Section and get it's position.
6182 //
6183 // Need code here to remove all the header/footers.
6184 //
6185 	pHdrFtr = pShadow->getHdrFtrSectionLayout();
6186 	fl_DocSectionLayout * pDSL = pHdrFtr->getDocSectionLayout();
6187 //
6188 // Repeat this code 4 times to remove all the DocSection Layouts.
6189 //
6190 	setCursorWait();
6191 	if(isHeader)
6192 	{
6193 		pHdrFtr = pDSL->getHeader();
6194 		if(pHdrFtr)
6195 		{
6196 			_removeThisHdrFtr(pHdrFtr);
6197 		}
6198 		pHdrFtr = pDSL->getHeaderEven();
6199 		if(pHdrFtr)
6200 		{
6201 			_removeThisHdrFtr(pHdrFtr);
6202 		}
6203 		pHdrFtr = pDSL->getHeaderFirst();
6204 		if(pHdrFtr)
6205 		{
6206 			_removeThisHdrFtr(pHdrFtr);
6207 		}
6208 		pHdrFtr = pDSL->getHeaderLast();
6209 		if(pHdrFtr)
6210 		{
6211 			_removeThisHdrFtr(pHdrFtr);
6212 		}
6213 	}
6214 	else
6215 	{
6216 		pHdrFtr = pDSL->getFooter();
6217 		if(pHdrFtr)
6218 		{
6219 			_removeThisHdrFtr(pHdrFtr);
6220 		}
6221 		pHdrFtr = pDSL->getFooterEven();
6222 		if(pHdrFtr)
6223 		{
6224 			_removeThisHdrFtr(pHdrFtr);
6225 		}
6226 		pHdrFtr = pDSL->getFooterFirst();
6227 		if(pHdrFtr)
6228 		{
6229 			_removeThisHdrFtr(pHdrFtr);
6230 		}
6231 		pHdrFtr = pDSL->getFooterLast();
6232 		if(pHdrFtr)
6233 		{
6234 			_removeThisHdrFtr(pHdrFtr);
6235 		}
6236 	}
6237 //
6238 // After erarsing the cursor, Restore to the point before all this mess started.
6239 //
6240 	_setPoint(curPoint);
6241 
6242 	// Signal PieceTable Changes have finished
6243 	_restorePieceTableState();
6244 
6245 	_generalUpdate();
6246 	updateScreen (); // fix 1803, force screen update/redraw
6247 
6248 	_updateInsertionPoint();
6249 	m_pDoc->endUserAtomicGlob();
6250 	clearCursorWait();
6251 	notifyListeners (AV_CHG_HDRFTR | AV_CHG_FMTSECTION);
6252 }
6253 
6254 /*!
6255  * Start edit header mode. If there is no header one will be inserted.
6256  * otherwise start editing the header on the current page.
6257  */
cmdEditHeader(void)6258 void FV_View::cmdEditHeader(void)
6259 {
6260 	_cmdEditHdrFtr(FL_HDRFTR_HEADER);
6261 	notifyListeners (AV_CHG_HDRFTR | AV_CHG_FMTSECTION);
6262 }
6263 
6264 /*!
6265  * Start edit footer mode. If there is no footer one will be inserted.
6266  * otherwise start editing the footer on the current page.
6267  */
cmdEditFooter(void)6268 void FV_View::cmdEditFooter(void)
6269 {
6270 	_cmdEditHdrFtr(FL_HDRFTR_FOOTER);
6271 	notifyListeners (AV_CHG_HDRFTR | AV_CHG_FMTSECTION);
6272 }
6273 
cmdAcceptRejectRevision(bool bReject,UT_sint32 xPos,UT_sint32 yPos)6274 void FV_View::cmdAcceptRejectRevision(bool bReject, UT_sint32 xPos, UT_sint32 yPos)
6275 {
6276 	UT_DEBUGMSG(( "FV_View::cmdAcceptRejectRevision [bReject=%d]\n",bReject ));
6277 
6278 	PT_DocPosition iStart, iEnd;
6279 	fl_BlockLayout * pBlock = NULL;
6280 	fp_Run *pRun = NULL;
6281 
6282 	// Signal PieceTable Change
6283 	_saveAndNotifyPieceTableChange();
6284 
6285 	if(isSelectionEmpty())
6286 	{
6287 		if(xPos || yPos) // if given 0,0 use current position
6288 		{
6289 			warpInsPtToXY(xPos, yPos,true);
6290 		}
6291 
6292 		pBlock = getCurrentBlock();
6293 		PT_DocPosition iRelPos = getPoint() - pBlock->getPosition(false);
6294 
6295 		pRun = pBlock->getFirstRun();
6296 		while (pRun && pRun->getNextRun() && pRun->getBlockOffset()+ pRun->getLength() <= iRelPos)
6297 			pRun= pRun->getNextRun();
6298 
6299 		UT_return_if_fail(pRun);
6300 
6301 		iStart = pBlock->getPosition(false) + pRun->getBlockOffset();
6302 		iEnd = pBlock->getPosition(false) + pRun->getBlockOffset() + pRun->getLength();
6303 
6304 	}
6305 	else
6306 	{
6307 		iStart = getPoint();
6308 		iEnd   = getSelectionAnchor();
6309 	}
6310 
6311 	// remove the selection, since things will get inserted, deleted, etc.
6312 	_clearSelection();
6313 
6314 	m_pDoc->acceptRejectRevision(bReject,iStart,iEnd,m_iViewRevision);
6315 	_restorePieceTableState();
6316 	_generalUpdate();
6317 }
6318 
cmdSetRevisionLevel(UT_uint32 i)6319 void FV_View::cmdSetRevisionLevel(UT_uint32 i)
6320 {
6321 	UT_return_if_fail( i <= PD_MAX_REVISION );
6322 	// first set the same level in Doc; we do this unconditionally,
6323 	// this way the doc will always save the level the user last used
6324 	// NB: the doc id and the view id can be differnt if the user
6325 	// changed it in some other view
6326 	m_pDoc->setShowRevisionId(i);
6327 
6328 	if(m_iViewRevision != i)
6329 	{
6330 		m_iViewRevision = i;
6331 
6332 		// need to rebuild the doc to reflect the new level ...
6333 		m_pLayout->rebuildFromHere(static_cast<fl_DocSectionLayout *>(m_pLayout->getFirstSection()));
6334 
6335 		// we have to force redraw here, see bug 10486
6336 		draw(NULL);
6337 	}
6338 }
6339 
6340 /*!
6341     finds the next/previous revision and sets selection to it
6342     TODO the selection will not cross block boundaries; it probably should
6343 
6344     \param bNext: if true the search is carried out in forward direction
6345     \return returns true on succes
6346 */
cmdFindRevision(bool bNext,UT_sint32 xPos,UT_sint32 yPos)6347 bool FV_View::cmdFindRevision(bool bNext, UT_sint32 xPos, UT_sint32 yPos)
6348 {
6349 	if(xPos || yPos)
6350 	{
6351 		// this is the case we were called from context menu ...
6352 		warpInsPtToXY(xPos, yPos,true);
6353 	}
6354 
6355 	if(!isSelectionEmpty())
6356 	{
6357 		_moveToSelectionEnd(bNext);
6358 	}
6359 
6360 	fl_BlockLayout * pBL =	getCurrentBlock();
6361 
6362 	if(!pBL)
6363 		return false;
6364 
6365 	fl_DocSectionLayout * pSL = pBL->getDocSectionLayout();
6366 
6367 	if(!pSL)
6368 		return false;
6369 
6370 	fp_Run * pRun;
6371 	UT_sint32 xPoint,yPoint,xPoint2,yPoint2,iPointHeight;
6372 	bool bDirection;
6373 
6374 	pRun = pBL->findPointCoords(getPoint(), false, xPoint,
6375 								yPoint, xPoint2, yPoint2,
6376 								iPointHeight, bDirection);
6377 
6378 	if(!pRun)
6379 		return false;
6380 
6381 	if(bNext)
6382 	{
6383 		pRun = pRun->getNextRun();
6384 
6385 		while(pSL)
6386 		{
6387 			while(pBL)
6388 			{
6389 				while(pRun)
6390 				{
6391 					if(pRun->containsRevisions() && !pRun->isHidden())
6392 					{
6393 						goto move_point;
6394 					}
6395 
6396 					pRun = pRun->getNextRun();
6397 				}
6398 
6399 				pBL = pBL->getNextBlockInDocument();
6400 			}
6401 
6402 			pSL = pSL->getNextDocSection();
6403 		}
6404 	}
6405 	else
6406 	{
6407 		pRun = pRun->getPrevRun();
6408 
6409 		while(pSL)
6410 		{
6411 			while(pBL)
6412 			{
6413 				while(pRun)
6414 				{
6415 					if(pRun->containsRevisions() && !pRun->isHidden())
6416 					{
6417 						goto move_point;
6418 					}
6419 
6420 					pRun = pRun->getPrevRun();
6421 				}
6422 
6423 				pBL = pBL->getPrevBlockInDocument();
6424 			}
6425 
6426 			pSL = pSL->getPrevDocSection();
6427 		}
6428 	}
6429 
6430 	return false;
6431 
6432  move_point:
6433 	UT_return_val_if_fail(pRun && pBL, false);
6434 
6435 	// we want to span the selection not only over this run, but also
6436 	// all subesequent runs that contain the same revions
6437 	// TODO: probably should do this across block/section boundaries
6438 	fp_Run * pRun2 = bNext ? pRun->getNextRun() : pRun->getPrevRun();
6439 	fp_Run * pOldRun2 = pRun;
6440 
6441 	PP_RevisionAttr * pR1 = pRun->getRevisions();
6442 
6443 	while(pRun2)
6444 	{
6445 		if(pRun2->containsRevisions() && !pRun2->isHidden())
6446 		{
6447 			// test the two runs, if their revions are the same
6448 			// include this one as well
6449 			PP_RevisionAttr * pR2 = pRun2->getRevisions();
6450 
6451 			if(!(*pR1 == *pR2))
6452 				break;
6453 		}
6454 		else
6455 		{
6456 			break;
6457 		}
6458 
6459 		pOldRun2 = pRun2;
6460 		pRun2 = bNext ? pRun2->getNextRun() : pRun2->getPrevRun();
6461 	}
6462 
6463 	// backtrack (we want pRun2 to be the last run in the selection
6464 	pRun2 = pOldRun2;
6465 	UT_return_val_if_fail(pRun2, false);
6466 
6467 	PT_DocPosition dpos1, dpos2;
6468 
6469 	if(bNext)
6470 	{
6471 		dpos1 = pBL->getPosition() + pRun->getBlockOffset();
6472 		dpos2 = pRun2->getBlock()->getPosition() + pRun2->getBlockOffset() + pRun2->getLength();
6473 	}
6474 	else
6475 	{
6476 		dpos1 = pRun2->getBlock()->getPosition() + pRun2->getBlockOffset();
6477 		dpos2 = pBL->getPosition() + pRun->getBlockOffset() + pRun->getLength();
6478 	}
6479 
6480 	cmdSelect(dpos1, dpos2);
6481 
6482 	return true;
6483 }
6484 
_updateDatesBeforeSave(bool bOverwriteCreated)6485 void FV_View::_updateDatesBeforeSave(bool bOverwriteCreated)
6486 {
6487     time_t now = time(NULL);
6488     std::string timeStr = ctime(&now);
6489 
6490     if (bOverwriteCreated)
6491     {
6492         m_pDoc->setMetaDataProp(PD_META_KEY_DATE, timeStr);
6493     } else
6494     {
6495         std::string metaValue;
6496         if(!m_pDoc->getMetaDataProp(PD_META_KEY_DATE, metaValue))
6497         {
6498             m_pDoc->setMetaDataProp(PD_META_KEY_DATE, timeStr);
6499         }
6500     }
6501 
6502     m_pDoc->setMetaDataProp(PD_META_KEY_DATE_LAST_CHANGED, timeStr);
6503 }
6504 
6505