/* AbiWord * Copyright (C) 2003 Dom Lachowicz * * 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., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #include #include #include #include "ut_assert.h" #include "ut_string.h" #include "ut_debugmsg.h" #include "ap_Dialog_Stylist.h" #include "ap_Strings.h" #include "xap_App.h" #include "xap_Dialog_Id.h" #include "xap_DialogFactory.h" #include "xap_Dlg_MessageBox.h" #include "fv_View.h" #include "pd_Document.h" #include "pd_Style.h" #include "pt_Types.h" #include "fp_Line.h" #include "fp_Run.h" #include "fp_ContainerObject.h" #include "fp_TableContainer.h" #include "fl_TableLayout.h" #include "fl_BlockLayout.h" #include "fl_DocLayout.h" #include "ut_timer.h" #include "pd_Document.h" AP_Dialog_Stylist::AP_Dialog_Stylist(XAP_DialogFactory * pDlgFactory, XAP_Dialog_Id id) : XAP_Dialog_Modeless(pDlgFactory,id), m_bIsModal(false), m_pDoc(NULL), m_pAutoUpdater(0), m_iTick(0), m_sCurStyle(""), m_pStyleTree(NULL), m_bStyleTreeChanged(true), m_bStyleChanged(true) { } AP_Dialog_Stylist::~AP_Dialog_Stylist(void) { stopUpdater(); DELETEP(m_pStyleTree); } void AP_Dialog_Stylist::setActiveFrame(XAP_Frame * /*pFrame*/) { updateDialog(); notifyActiveFrame(getActiveFrame()); } void AP_Dialog_Stylist::startUpdater(void) { m_pAutoUpdater = UT_Timer::static_constructor(autoUpdate,this); m_pAutoUpdater->set(500); m_pAutoUpdater->start(); } /*! * Apply current style to the current selection in the current view */ void AP_Dialog_Stylist::Apply(void) { if(!getActiveFrame()) return; FV_View * pView = static_cast(getActiveFrame()->getCurrentView()); if(pView->getPoint() == 0) { return; } pView->setStyle(getCurStyle()->utf8_str()); pView->notifyListeners(AV_CHG_MOTION | AV_CHG_HDRFTR); } void AP_Dialog_Stylist::stopUpdater(void) { if(m_pAutoUpdater == NULL) { return; } m_pAutoUpdater->stop(); DELETEP(m_pAutoUpdater); m_pAutoUpdater = NULL; } UT_sint32 AP_Dialog_Stylist::getNumStyles(void) const { if(m_pStyleTree == NULL) { return 0; } return m_pStyleTree->getNumStyles(); } /*! * Autoupdater of the dialog. */ void AP_Dialog_Stylist::autoUpdate(UT_Worker * pTimer) { UT_return_if_fail (pTimer); // this is a static callback method and does not have a 'this' pointer AP_Dialog_Stylist * pDialog = static_cast(pTimer->getInstanceData()); pDialog->updateDialog(); } /*! * This method actually updates the dialog, in particular the style Tree and * the current style. */ void AP_Dialog_Stylist::updateDialog(void) { XAP_Frame * frame = getActiveFrame(); if (frame) { // Handshaking code FV_View * pView = static_cast(frame->getCurrentView()); if(pView->getPoint() == 0) { return; } PD_Document * pDoc = pView->getDocument(); if(m_pStyleTree == NULL) { m_pStyleTree = new Stylist_tree(pDoc); } if((m_iTick != pView->getTick()) || (m_pDoc != pDoc)) { m_iTick = pView->getTick(); if((pDoc != m_pDoc) || (static_cast(pDoc->getStyleCount()) != getNumStyles())) { m_pDoc = pDoc; m_pStyleTree->buildStyles(pDoc); if(!m_bIsModal) // fill the current style if Modeless { const char * pszStyle; pView->getStyle(&pszStyle); m_sCurStyle = pszStyle; } m_bStyleTreeChanged =true; setStyleInGUI(); return; } const char * pszStyle; pView->getStyle(&pszStyle); UT_UTF8String sCurViewStyle; if(!m_bIsModal) { sCurViewStyle = pszStyle; } else { m_bStyleChanged =true; setStyleInGUI(); return; } if((sCurViewStyle.size ()) > 0 && m_sCurStyle.size() == 0) { m_sCurStyle = sCurViewStyle; m_bStyleChanged =true; setStyleInGUI(); return; } if(sCurViewStyle != m_sCurStyle) { m_sCurStyle = sCurViewStyle; m_bStyleChanged =true; setStyleInGUI(); return; } } } setAllSensitivities(); } /*! * Finalize the dialog. */ void AP_Dialog_Stylist::finalize(void) { stopUpdater(); modeless_cleanup(); } void AP_Dialog_Stylist::setAllSensitivities() { XAP_Frame *frame = XAP_App::getApp()->getLastFocussedFrame(); if (frame) { setSensitivity(true); } else { setSensitivity(false); } } /////////////////////////////////////////////////////////////////////////// /*! * This class holds the current style tree and provides a useful interface * to the tree for the GUI. */ Stylist_tree::Stylist_tree(PD_Document *pDoc) { m_vecAllStyles.clear(); m_vecStyleRows.clear(); buildStyles(pDoc); } Stylist_tree::~Stylist_tree(void) { UT_DEBUGMSG(("Deleteing Stylist_tree %p \n",this)); UT_VECTOR_PURGEALL(Stylist_row *, m_vecStyleRows); } /*! * This method builds the tree of styles from the Document given. */ void Stylist_tree::buildStyles(PD_Document * pDoc) { UT_sint32 numStyles = static_cast(pDoc->getStyleCount()); UT_sint32 i = 0; m_vecAllStyles.clear(); UT_VECTOR_PURGEALL(Stylist_row *, m_vecStyleRows); m_vecStyleRows.clear(); UT_GenericVector vecStyles; const PD_Style * pStyle = NULL; UT_DEBUGMSG(("In Build styles num styles in doc %d \n",numStyles)); UT_GenericVector * pStyles = NULL; pDoc->enumStyles(pStyles); UT_return_if_fail( pStyles ); for(i=0; i < numStyles; i++) { pStyle = pStyles->getNthItem(i); m_vecAllStyles.addItem(pStyle); vecStyles.addItem(pStyle); } delete pStyles; // // OK now build the tree of Styles // // Start with the heading styles. // const XAP_StringSet * pSS = XAP_App::getApp()->getStringSet (); Stylist_row * pStyleRow = new Stylist_row(); UT_UTF8String sTmp; pSS->getValueUTF8(AP_STRING_ID_DLG_Stylist_HeadingStyles, sTmp); pStyleRow->setRowName(sTmp); m_vecStyleRows.addItem(pStyleRow); for(i=0; i< numStyles; i++) { pStyle = vecStyles.getNthItem(i); if(isHeading(pStyle)) { sTmp = pStyle->getName(); pStyleRow->addStyle(sTmp); vecStyles.setNthItem(i,NULL,NULL); UT_DEBUGMSG(("Adding heading style %s \n",sTmp.utf8_str())); } } // // Next the list styles. // pStyleRow = new Stylist_row(); pSS->getValueUTF8(AP_STRING_ID_DLG_Stylist_ListStyles, sTmp); pStyleRow->setRowName(sTmp); m_vecStyleRows.addItem(pStyleRow); for(i=0; i< numStyles; i++) { pStyle = vecStyles.getNthItem(i); if(pStyle && isList(pStyle)) { sTmp = pStyle->getName(); pStyleRow->addStyle(sTmp); vecStyles.setNthItem(i,NULL,NULL); UT_DEBUGMSG(("Adding List style %s \n",sTmp.utf8_str())); } } // // Now the Footnote/Endnote. // pStyleRow = new Stylist_row(); pSS->getValueUTF8(AP_STRING_ID_DLG_Stylist_FootnoteStyles, sTmp); pStyleRow->setRowName(sTmp); m_vecStyleRows.addItem(pStyleRow); for(i=0; i< numStyles; i++) { pStyle = vecStyles.getNthItem(i); if(pStyle && isFootnote(pStyle)) { sTmp = pStyle->getName(); pStyleRow->addStyle(sTmp); vecStyles.setNthItem(i,NULL,NULL); UT_DEBUGMSG(("Adding Footnote style %s \n",sTmp.utf8_str())); } } // // Now the user-defined // pStyleRow = new Stylist_row(); pSS->getValueUTF8(AP_STRING_ID_DLG_Stylist_UserStyles, sTmp); pStyleRow->setRowName(sTmp); UT_sint32 iCount = 0; for(i=0; i< numStyles; i++) { pStyle = vecStyles.getNthItem(i); if(pStyle && isUser(pStyle)) { sTmp = pStyle->getName(); pStyleRow->addStyle(sTmp); vecStyles.setNthItem(i,NULL,NULL); iCount++; UT_DEBUGMSG(("Adding User-defined style %s \n",sTmp.utf8_str())); } } if(iCount > 0) { m_vecStyleRows.addItem(pStyleRow); } else { DELETEP(pStyleRow); } // // Now everything else // pSS->getValueUTF8(AP_STRING_ID_DLG_Stylist_MiscStyles, sTmp); pStyleRow = new Stylist_row(); pStyleRow->setRowName(sTmp); m_vecStyleRows.addItem(pStyleRow); for(i=0; i< numStyles; i++) { pStyle = vecStyles.getNthItem(i); if(pStyle) { sTmp = pStyle->getName(); pStyleRow->addStyle(sTmp); vecStyles.setNthItem(i,NULL,NULL); UT_DEBUGMSG(("Adding style %s \n",sTmp.utf8_str())); } } } /*! * Returns true if the style is withinthe "Heading" type of styles. */ bool Stylist_tree::isHeading(const PD_Style * pStyle, UT_sint32 iDepth) const { if(pStyle == NULL) { return false; } if(strstr(pStyle->getName(),"Heading") != 0) { return true; } PD_Style * pUpStyle = pStyle->getBasedOn(); if(pUpStyle != NULL && iDepth > 0) { return isHeading(pUpStyle,iDepth-1); } return false; } /*! * Returns true if the style is withinthe "List" type of styles. */ bool Stylist_tree::isList(const PD_Style * pStyle, UT_sint32 iDepth) const { if(pStyle == NULL) { return false; } if(strstr(pStyle->getName(),"List") != 0) { return true; } PD_Style * pUpStyle = pStyle->getBasedOn(); if(pUpStyle != NULL && iDepth > 0) { return isList(pUpStyle,iDepth-1); } return false; } /*! * Returns true if the style is withinthe "Footnote/Endnote" type of styles. */ bool Stylist_tree::isFootnote(const PD_Style * pStyle, UT_sint32 iDepth) const { if(pStyle == NULL) { return false; } if((strstr(pStyle->getName(),"Footnote") != 0) || (strstr(pStyle->getName(),"Endnote") != 0)) { return true; } PD_Style * pUpStyle = pStyle->getBasedOn(); if(pUpStyle != NULL && iDepth > 0) { return isFootnote(pUpStyle,iDepth-1); } return false; } /*! * Returns true if the style is a userdefined style. */ bool Stylist_tree::isUser(const PD_Style * pStyle) const { if(pStyle == NULL) { return false; } return pStyle->isUserDefined(); } /*! * Return the number of rows in the tree. */ UT_sint32 Stylist_tree::getNumRows(void) { return m_vecStyleRows.getItemCount(); } /*! * Return the row and column address of the style given. If not found return * false. */ bool Stylist_tree::findStyle(UT_UTF8String & sStyleName,UT_sint32 & row, UT_sint32 & col) { UT_sint32 i =0; UT_sint32 numRows = getNumRows(); bool bFound = false; for(i=0; (i(m_vecStyleRows.getNthItem(i)); bFound = pStyleRow->findStyle(sStyleName,col); if(bFound) { row = i; return true; } } row = -1; col = -1; return false; } /*! * Return the style at the row and column given. If the (row,col) address is * valid, return false. */ bool Stylist_tree::getStyleAtRowCol(UT_UTF8String & sStyle,UT_sint32 row, UT_sint32 col) { if(row > getNumRows() || (row < 0)) { return false; } Stylist_row * pStyleRow = static_cast(m_vecStyleRows.getNthItem(row)); bool bFound = pStyleRow->getStyle(sStyle,col); return bFound; } /*! * return the number of columns at the row given. * If the row is invalid return 0. */ UT_sint32 Stylist_tree::getNumCols(UT_sint32 row) { if(row > getNumRows() || (row < 0)) { return 0; } Stylist_row * pStyleRow = static_cast(m_vecStyleRows.getNthItem(row)); return pStyleRow->getNumCols(); } /*! * Return the total number of styles in the tree. */ UT_sint32 Stylist_tree::getNumStyles(void) const { return m_vecAllStyles.getItemCount(); } /*! * return the name of the row given. If the row is invalid return false; */ bool Stylist_tree::getNameOfRow(UT_UTF8String &sName, UT_sint32 row) { if(row > getNumRows() || (row<0) ) { return false; } Stylist_row * pStyleRow = static_cast(m_vecStyleRows.getNthItem(row)); pStyleRow->getRowName(sName); return true; } ////////////////////////////////////////////////////////////////////////// /*! * This class holds a row of style names and a useful API to access them. */ Stylist_row::Stylist_row(void): m_sRowName("") { m_vecStyles.clear(); UT_DEBUGMSG(("Creating Stylist_row %p \n",this)); } Stylist_row::~Stylist_row(void) { UT_DEBUGMSG(("Deleteing Stylist_row %p num styles %d\n",this,m_vecStyles.getItemCount())); UT_VECTOR_PURGEALL(UT_UTF8String *, m_vecStyles); } void Stylist_row::addStyle(UT_UTF8String & sStyle) { UT_UTF8String * psStyle = new UT_UTF8String(sStyle); m_vecStyles.addItem(psStyle); } void Stylist_row::setRowName(UT_UTF8String & sRowName) { m_sRowName = sRowName; } void Stylist_row::getRowName(UT_UTF8String & sRowName) { sRowName = m_sRowName; } UT_sint32 Stylist_row::getNumCols(void) { return m_vecStyles.getItemCount(); } bool Stylist_row::findStyle(UT_UTF8String & sStyleName, UT_sint32 & col) { UT_sint32 i = 0; UT_sint32 numCols = getNumCols(); bool bFound = false; for(i=0; (i getNumCols()) || (col < 0)) { return false; } UT_UTF8String * psStyle = m_vecStyles.getNthItem(col); sStyleName = *psStyle; return true; }