/* AbiWord * Copyright (c) 2003 Martin Sevior * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301 USA. */ #include "fv_Selection.h" #include "fl_DocLayout.h" #include "pd_Document.h" #include "ut_units.h" #include "fl_BlockLayout.h" #include "fp_Line.h" #include "fp_Run.h" #include "pf_Frag.h" #include "pf_Frag_Strux.h" #include "fl_TableLayout.h" #include "pd_Document.h" #include "ie_exp.h" #include "ie_exp_RTF.h" #include "fl_TOCLayout.h" #include "ie_imp.h" #include "ie_imp_RTF.h" #include "ut_bytebuf.h" #include "fv_View.h" FV_Selection::FV_Selection (FV_View * pView) : m_pView (pView), m_iSelectionMode(FV_SelectionMode_NONE), m_iPrevSelectionMode(FV_SelectionMode_NONE), m_iSelectAnchor(0), m_iSelectLeftAnchor(0), m_iSelectRightAnchor(0), m_pTableOfSelectedColumn(NULL), m_pSelectedTOC(NULL), m_bSelectAll(false) { UT_ASSERT (pView); m_vecSelRanges.clear(); m_vecSelRTFBuffers.clear(); } FV_Selection::~FV_Selection() { m_pTableOfSelectedColumn = NULL; m_pSelectedTOC = NULL; UT_VECTOR_PURGEALL(PD_DocumentRange *,m_vecSelRanges); UT_VECTOR_PURGEALL(UT_ByteBuf *,m_vecSelRTFBuffers); UT_VECTOR_PURGEALL(FV_SelectionCellProps *,m_vecSelCellProps); } void FV_Selection::checkSelectAll(void) { fl_SectionLayout * pSL = m_pView->m_pLayout->getLastSection(); if(pSL == NULL) return; if(m_pView->m_pDoc->isPieceTableChanging()) { return; } if(m_pView->m_pLayout->isLayoutFilling()) { return; } PT_DocPosition posLow = m_iSelectAnchor; PT_DocPosition posHigh = m_pView->getPoint(); if(posHigh < posLow) { posHigh = m_iSelectAnchor; posLow = m_pView->getPoint(); } PT_DocPosition posBeg,posEnd=0; m_pView->getEditableBounds(false,posBeg); m_pView->getEditableBounds(true,posEnd); xxx_UT_DEBUGMSG(("posLow %d posBeg %d posHigh %d posEnd %d\n",posLow,posBeg,posHigh,posEnd)); bool bSelAll = ((posBeg >= posLow) && (posEnd == posHigh)); setSelectAll(bSelAll); } void FV_Selection::setSelectAll(bool bSelectAll) { xxx_UT_DEBUGMSG(("Select All = %d \n",bSelectAll)); m_bSelectAll = bSelectAll; } void FV_Selection::setMode(FV_SelectionMode iSelMode) { if( (m_iSelectionMode != FV_SelectionMode_NONE) || (iSelMode != FV_SelectionMode_NONE)) { m_iPrevSelectionMode = m_iSelectionMode; } if((m_iSelectionMode == FV_SelectionMode_TOC) && (m_iSelectionMode != iSelMode)) { if(m_pSelectedTOC) { m_pSelectedTOC->setSelected(false); } m_pSelectedTOC = NULL; } m_iSelectionMode = iSelMode; if(m_iSelectionMode != FV_SelectionMode_NONE) { m_pTableOfSelectedColumn = NULL; UT_VECTOR_PURGEALL(PD_DocumentRange *,m_vecSelRanges); UT_VECTOR_PURGEALL(UT_ByteBuf *,m_vecSelRTFBuffers); UT_VECTOR_PURGEALL(FV_SelectionCellProps *,m_vecSelCellProps); m_vecSelRanges.clear(); m_vecSelRTFBuffers.clear(); m_vecSelCellProps.clear(); } setSelectAll(false); } void FV_Selection::setTOCSelected(fl_TOCLayout * pTOCL) { UT_return_if_fail(pTOCL); setMode(FV_SelectionMode_TOC); m_pSelectedTOC = pTOCL; m_iSelectAnchor = pTOCL->getPosition(); pTOCL->setSelected(true); setSelectAll(false); } void FV_Selection::pasteRowOrCol(void) { pf_Frag_Strux* cellSDH, *tableSDH; PT_DocPosition pos = m_pView->getPoint(); if(m_iPrevSelectionMode == FV_SelectionMode_TableColumn) { // // GLOB stuff together so it undo's in one go. // getDoc()->beginUserAtomicGlob(); // // Insert a column after the current column // m_pView->cmdInsertCol(m_pView->getPoint(),false); // // Now do all the encapsulating stuff for piecetable manipulations. // // Signal PieceTable Change m_pView->_saveAndNotifyPieceTableChange(); // Turn off list updates getDoc()->disableListUpdates(); if (!m_pView->isSelectionEmpty()) { m_pView->_clearSelection(); } getDoc()->setDontImmediatelyLayout(true); pos = m_pView->getPoint(); PT_DocPosition posTable,posCell; UT_sint32 iLeft,iRight,iTop,iBot; posCell = 0; m_pView->getCellParams(pos, &iLeft, &iRight,&iTop,&iBot); bool bRes = getDoc()->getStruxOfTypeFromPosition(pos,PTX_SectionCell,&cellSDH); bRes = getDoc()->getStruxOfTypeFromPosition(pos,PTX_SectionTable,&tableSDH); UT_return_if_fail(bRes); posTable = getDoc()->getStruxPosition(tableSDH) + 1; UT_sint32 numRows = 0; UT_sint32 numCols = 0; UT_sint32 i = 0; getDoc()-> getRowsColsFromTableSDH(tableSDH, m_pView->isShowRevisions(), m_pView->getRevisionLevel(), &numRows, &numCols); PD_DocumentRange DocRange(getDoc(),posCell,posCell); for(i=0; ifindCellPosAt(posTable,i,iLeft)+2; m_pView->setPoint(posCell); PD_DocumentRange * pR = getNthSelection(i); if(pR->m_pos1 == pR->m_pos2) { // // Dont paste empty cells // continue; } UT_ByteBuf * pBuf = m_vecSelRTFBuffers.getNthItem(i); const unsigned char * pData = pBuf->getPointer(0); UT_uint32 iLen = pBuf->getLength(); DocRange.m_pos1 = posCell; DocRange.m_pos2 = posCell; IE_Imp_RTF * pImpRTF = new IE_Imp_RTF(getDoc()); pImpRTF->pasteFromBuffer(&DocRange,pData,iLen); DELETEP(pImpRTF); fl_SectionLayout * pSL = m_pView->getCurrentBlock()->getSectionLayout(); pSL->checkAndAdjustCellSize(); } getDoc()->endUserAtomicGlob(); getDoc()->setDontImmediatelyLayout(false); m_pView->_generalUpdate(); // restore updates and clean up dirty lists getDoc()->enableListUpdates(); getDoc()->updateDirtyLists(); // Signal PieceTable Changes have finished m_pView->_restorePieceTableState(); // Put the insertion point in a legal position // m_pView->notifyListeners(AV_CHG_MOTION); m_pView->_fixInsertionPointCoords(); m_pView->_ensureInsertionPointOnScreen(); } else { } } fl_TableLayout * FV_Selection::getTableLayout(void) const { return m_pTableOfSelectedColumn; } PD_Document * FV_Selection::getDoc(void) const { return m_pView->getDocument(); } FL_DocLayout * FV_Selection::getLayout(void) const { return m_pView->getLayout(); } PT_DocPosition FV_Selection::getSelectionAnchor(void) const { if((m_iSelectionMode < FV_SelectionMode_Multiple) || (m_vecSelRanges.getItemCount() == 0)) { return m_iSelectAnchor; } PD_DocumentRange * pDocRange = m_vecSelRanges.getNthItem(0); return pDocRange->m_pos1; } void FV_Selection::setSelectionAnchor(PT_DocPosition pos) { m_iSelectAnchor = pos; fl_SectionLayout * pSL = m_pView->m_pLayout->getLastSection(); if(pSL == NULL) return; PT_DocPosition posLow = m_iSelectAnchor; PT_DocPosition posHigh = m_pView->getPoint(); if(posHigh < posLow) { posHigh = m_iSelectAnchor; posLow = m_pView->getPoint(); } PT_DocPosition posBeg,posEnd=0; m_pView->getEditableBounds(false,posBeg); m_pView->getEditableBounds(true,posEnd); xxx_UT_DEBUGMSG(("posLow %d posBeg %d posHigh %d posEnd %d\n",posLow,posBeg,posHigh,posEnd)); bool bSelAll = ((posBeg >= posLow) && (posEnd <= posHigh)); setSelectAll(bSelAll); } PT_DocPosition FV_Selection::getSelectionLeftAnchor(void) const { if((m_iSelectionMode < FV_SelectionMode_Multiple) || (m_vecSelRanges.getItemCount() == 0)) { return m_iSelectLeftAnchor; } PD_DocumentRange * pDocRange = m_vecSelRanges.getNthItem(0); return pDocRange->m_pos1; } void FV_Selection::setSelectionLeftAnchor(PT_DocPosition pos) { if(pos == 0) return; m_iSelectLeftAnchor = pos; PT_DocPosition posBeg,posEnd=0; m_pView->getEditableBounds(false,posBeg); m_pView->getEditableBounds(true,posEnd); bool bSelAll = ((posBeg >= m_iSelectLeftAnchor) && (posEnd <= m_iSelectRightAnchor)); xxx_UT_DEBUGMSG(("setleft posBeg %d left %d posEnd %d right %d\n",posBeg,m_iSelectLeftAnchor,posEnd,m_iSelectRightAnchor)); setSelectAll(bSelAll); } PT_DocPosition FV_Selection::getSelectionRightAnchor(void) const { if((m_iSelectionMode < FV_SelectionMode_Multiple) || (m_vecSelRanges.getItemCount() == 0) ) { return m_iSelectRightAnchor; } PD_DocumentRange * pDocRange = m_vecSelRanges.getNthItem(0); return pDocRange->m_pos2; } void FV_Selection::setSelectionRightAnchor(PT_DocPosition pos) { if(pos == 0) return; m_iSelectRightAnchor = pos; PT_DocPosition posBeg,posEnd=0; m_pView->getEditableBounds(false,posBeg); m_pView->getEditableBounds(true,posEnd); bool bSelAll = ((posBeg >= m_iSelectLeftAnchor) && (posEnd <= m_iSelectRightAnchor)); xxx_UT_DEBUGMSG(("setRight posBeg %d left %d posEnd %d right %d\n",posBeg,m_iSelectLeftAnchor,posEnd,m_iSelectRightAnchor)); setSelectAll(bSelAll); } bool FV_Selection::isPosSelected(PT_DocPosition pos) const { if(m_iSelectionMode == FV_SelectionMode_NONE) { return false; } if(m_iSelectionMode < FV_SelectionMode_Multiple) { if(m_iSelectAnchor == m_pView->getPoint()) { return false; } xxx_UT_DEBUGMSG(("m_iSelectAnchor %d \n",m_iSelectAnchor)); PT_DocPosition posLow = m_iSelectAnchor; PT_DocPosition posHigh = m_pView->getPoint(); if(posHigh < posLow) { posHigh = m_iSelectAnchor; posLow = m_pView->getPoint(); } return ((pos >= posLow) && (pos <=posHigh)); } UT_sint32 i =0; for(i=0; i < m_vecSelRanges.getItemCount(); i++) { PD_DocumentRange * pDocRange = m_vecSelRanges.getNthItem(i); xxx_UT_DEBUGMSG(("Looking at pos %d low %d high %d \n",pos, pDocRange->m_pos1,pDocRange->m_pos2 )); if ((pos >= pDocRange->m_pos1) && (pos <= pDocRange->m_pos2+1)) { return true; } } return false; } bool FV_Selection::isSelected(void) const { return FV_SelectionMode_NONE != m_iSelectionMode; } void FV_Selection::clearSelection(void) { setMode(FV_SelectionMode_NONE); setSelectAll(false); } void FV_Selection::setTableLayout(fl_TableLayout * pFL) { UT_ASSERT((m_iSelectionMode == FV_SelectionMode_TableColumn) || ( m_iSelectionMode == FV_SelectionMode_TableRow)); m_pTableOfSelectedColumn = pFL; } /*! * Add a range to the list of selected regions as defined by posLow, posHigh. * If bAddData is true also make a copy of the selected text in RTF format. */ void FV_Selection::addSelectedRange(PT_DocPosition /*posLow*/, PT_DocPosition /*posHigh*/, bool /*bAddData*/) { } /*! * Add a cell to the list of selected regions. */ void FV_Selection::addCellToSelection(fl_CellLayout * pCell) { UT_ASSERT((m_iSelectionMode == FV_SelectionMode_TableColumn) || ( m_iSelectionMode == FV_SelectionMode_TableRow)); pf_Frag_Strux* sdhEnd = NULL; pf_Frag_Strux* sdhStart = pCell->getStruxDocHandle(); PT_DocPosition posLow = getDoc()->getStruxPosition(sdhStart) +1; // First block UT_DebugOnly bres = getDoc()->getNextStruxOfType(sdhStart,PTX_EndCell,&sdhEnd); PT_DocPosition posHigh = getDoc()->getStruxPosition(sdhEnd) -1; UT_ASSERT(bres && sdhEnd); PD_DocumentRange * pDocRange = new PD_DocumentRange(getDoc(),posLow,posHigh); m_vecSelRanges.addItem(pDocRange); IE_Exp_RTF * pExpRtf = new IE_Exp_RTF(pDocRange->m_pDoc); UT_ByteBuf * pByteBuf = new UT_ByteBuf; if (pExpRtf) { if(posLow < posHigh) { pDocRange->m_pos1++; pDocRange->m_pos2++; } pExpRtf->copyToBuffer(pDocRange,pByteBuf); if(posLow < posHigh) { pDocRange->m_pos1--; pDocRange->m_pos2--; } DELETEP(pExpRtf); } m_vecSelRTFBuffers.addItem(pByteBuf); FV_SelectionCellProps * pCellProps = new FV_SelectionCellProps; UT_sint32 iLeft,iRight,iTop,iBot; m_pView->getCellParams(posLow,&iLeft,&iRight,&iTop,&iBot); UT_DEBUGMSG(("In Selection left %d right %d top %d bot %d \n",iLeft,iRight,iTop,iBot)); pCellProps->m_iLeft = iLeft; pCellProps->m_iRight = iRight; pCellProps->m_iTop = iTop; pCellProps->m_iBot = iBot; m_vecSelCellProps.addItem(pCellProps); setSelectAll(false); } /*! * Return the ith selection. */ PD_DocumentRange * FV_Selection::getNthSelection(UT_sint32 i) const { if(i >= getNumSelections()) { return NULL; } PD_DocumentRange * pDocRange = m_vecSelRanges.getNthItem(i); return pDocRange; } /*! * Return the number of active selections. */ UT_sint32 FV_Selection::getNumSelections(void) const { return m_vecSelRanges.getItemCount(); }