/* This file is part of the KOffice project * Copyright (C) 2005 Thomas Zander * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; version 2. * This library 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "KWDocument.h" #include "KWFrameViewManager.h" #include #include #include #include #include #include #include #include "tqpopupmenu.h" #include KWFrameViewManager::KWFrameViewManager() : TQObject() { setName("KWFrameViewManager"); m_queueRequested = false; m_blockEvents = false; } KWFrameViewManager::KWFrameViewManager(KWDocument *doc) { m_queueRequested = false; m_blockEvents = true; TQPtrListIterator frameSets = doc->framesetsIterator(); while(frameSets.current()) { slotFrameSetAdded(*frameSets); ++frameSets; } m_blockEvents = false; connect(doc, TQ_SIGNAL( sigFrameSetAdded(KWFrameSet*)), TQ_SLOT( slotFrameSetAdded(KWFrameSet*))); connect(doc, TQ_SIGNAL( sigFrameSetRemoved(KWFrameSet*)), TQ_SLOT( slotFrameSetRemoved(KWFrameSet*))); recalculateFrameCache(); } KWFrameViewManager::~KWFrameViewManager() { TQValueListIterator events = m_frameEvents.begin(); while(events != m_frameEvents.end()) { delete (*events); ++events; } } void KWFrameViewManager::addKWFramesListener(KWFramesListener *listener) { m_framesListener.append(listener); } void KWFrameViewManager::removeKWFramesListener(KWFramesListener *listener) { m_framesListener.remove(listener); } void KWFrameViewManager::slotFrameSetAdded(KWFrameSet *fs) { if(! m_blockEvents) m_frameEvents.append(new FrameEvent(FrameEvent::FrameSetAdded, fs)); connect(fs, TQ_SIGNAL( sigFrameAdded(KWFrame*)), TQ_SLOT( slotFrameAdded(KWFrame *))); connect(fs, TQ_SIGNAL( sigFrameRemoved(KWFrame*)), TQ_SLOT( slotFrameRemoved(KWFrame *))); connect(fs, TQ_SIGNAL( sigNameChanged(KWFrameSet*)), TQ_SLOT( slotFrameSetRenamed(KWFrameSet *))); TQPtrListIterator frames = fs->frameIterator(); while(frames.current()) { KWFrame *f = frames.current(); slotFrameAdded(f); ++frames; } requestFireEvents(); } void KWFrameViewManager::slotFrameSetRemoved(KWFrameSet *fs) { if(! m_blockEvents) m_frameEvents.append(new FrameEvent(FrameEvent::FrameSetRemoved, fs)); disconnect(fs, TQ_SIGNAL( sigFrameAdded(KWFrame*)), this, TQ_SLOT( slotFrameAdded(KWFrame *))); disconnect(fs, TQ_SIGNAL( sigFrameRemoved(KWFrame*)), this, TQ_SLOT( slotFrameRemoved(KWFrame *))); disconnect(fs, TQ_SIGNAL( sigNameChanged(KWFrameSet*)), this, TQ_SLOT( slotFrameSetRenamed(KWFrameSet *))); TQPtrListIterator frames = fs->frameIterator(); while(frames.current()) { KWFrame *f = frames.current(); slotFrameRemoved(f); ++frames; } requestFireEvents(); } void KWFrameViewManager::slotFrameAdded(KWFrame *f) { if(! m_blockEvents) m_frameEvents.append(new FrameEvent(FrameEvent::FrameAdded, f)); m_frames.append(new KWFrameView(this, f)); requestFireEvents(); } void KWFrameViewManager::slotFrameRemoved(KWFrame *f) { if(! m_blockEvents) m_frameEvents.append(new FrameEvent(FrameEvent::FrameRemoved, f)); TQValueListIterator frames = m_frames.begin(); while(frames != m_frames.end()) { KWFrameView *fv = *frames; if(fv->frame() == f) { if(fv->selected()) m_frameEvents.append(new FrameEvent(FrameEvent::FrameSelectionChanged)); m_frames.remove(frames); delete fv; break; } ++frames; } requestFireEvents(); } void KWFrameViewManager::slotFrameMoved(KWFrame *f, double previousYPosition) { Q_UNUSED(previousYPosition); // to be used for the page caches to mark them dirty if(! m_blockEvents) m_frameEvents.append(new FrameEvent(FrameEvent::FrameMoved, f)); // TODO; KWFrameList update?? // update our caches.. requestFireEvents(); } void KWFrameViewManager::slotFrameResized(KWFrame *f) { if(! m_blockEvents) m_frameEvents.append(new FrameEvent(FrameEvent::FrameResized, f)); // update our caches.. requestFireEvents(); } void KWFrameViewManager::slotFrameSelectionChanged() { if(! m_blockEvents) m_frameEvents.append(new FrameEvent(FrameEvent::FrameSelectionChanged)); // update our caches.. requestFireEvents(); } void KWFrameViewManager::slotFrameSetRenamed(KWFrameSet *fs) { if(! m_blockEvents) m_frameEvents.append(new FrameEvent(FrameEvent::FrameSetRenamed, fs)); requestFireEvents(); } void KWFrameViewManager::requestFireEvents() { if(m_queueRequested && !m_blockEvents) return; m_queueRequested = true; TQTimer::singleShot ( 0, this, TQ_SLOT(fireEvents()) ); } void KWFrameViewManager::fireEvents() { m_queueRequested = false; if(m_frameEvents.isEmpty()) return; recalculateFrameCache(); TQValueList copy(m_frameEvents); m_frameEvents.clear(); TQValueList resizedFrames; TQValueList movedFrames; TQValueList listenersCopy(m_framesListener); bool selectionChangedFired=false; TQValueListIterator events = copy.begin(); while(events != copy.end()) { FrameEvent *event = *events; // emit based. if(!selectionChangedFired && event->m_action == FrameEvent::FrameSelectionChanged) { emit sigFrameSelectionChanged(); selectionChangedFired = true; // only fire ones. } else if(event->m_action == FrameEvent::FrameSetRenamed) { TQPtrListIterator frames = event->m_frameSet->frameIterator(); for(;frames.current();++frames) { if(view(frames.current())->selected()) { emit sigFrameSetRenamed(); break; } } } else if(event->m_action == FrameEvent::FrameResized) { resizedFrames.append(event->m_frame); } else if(event->m_action == FrameEvent::FrameMoved) { movedFrames.append(event->m_frame); } // listener based TQValueListIterator listeners = listenersCopy.begin(); while(listeners != listenersCopy.end()) { if(event->m_action == FrameEvent::FrameRemoved) (*listeners)->frameRemoved(event->m_frame); else if(event->m_action == FrameEvent::FrameAdded) (*listeners)->frameAdded(event->m_frame); else if(event->m_action == FrameEvent::FrameSetRemoved) (*listeners)->frameSetRemoved(event->m_frameSet); else if(event->m_action == FrameEvent::FrameSetAdded) (*listeners)->frameSetAdded(event->m_frameSet); ++listeners; } delete event; events = copy.remove(events); } if(resizedFrames.count() > 0) emit sigFrameResized(resizedFrames); if(movedFrames.count() > 0) emit sigFrameMoved(movedFrames); } void KWFrameViewManager::recalculateFrameCache() { // TODO :) design and implement a cache... // list of frames sorted on y-coord, with an additional list containing a jump-index kdDebug(31001) << "recalculateFrameCache " << m_frames.count() << " frames are currently registred" << endl; } KWFrameView *KWFrameViewManager::view(const KoPoint &point, SelectionType selected, bool borderOnly) const { TQValueVector framesThatAreHit = framesAt(point, borderOnly); bool foundCycleFrame = false; TQValueVector::iterator sortedFrames = framesThatAreHit.begin(); while(sortedFrames != framesThatAreHit.end()) { if(selected == nextUnselected) { if((*sortedFrames)->selected() ) foundCycleFrame = true; else if(foundCycleFrame && !(*sortedFrames)->selected() ) return *sortedFrames; } else if(selected == frameOnTop) return *sortedFrames; else { // not cycle, so simply a selected check. if((*sortedFrames)->selected() == (selected == KWFrameViewManager::selected )) return *sortedFrames; } ++sortedFrames; } if(selected == nextUnselected && framesThatAreHit.count() > 0) return framesThatAreHit[0]; return 0; } TQValueVector KWFrameViewManager::framesAt(const KoPoint &point, bool borderOnly) const { TQValueVector framesThatAreHit; // This is probably the slowest and worst way to do it, mark this for optimalisation! for(TQValueListConstIterator frames = m_frames.begin(); frames != m_frames.end(); ++frames) { if(! (*frames)->frame()->frameSet()->isVisible()) continue; if(borderOnly && (*frames)->isBorderHit(point) || !borderOnly && (*frames)->contains(point)) framesThatAreHit.append(*frames); } // sort on z-ordering; top on first std::sort(framesThatAreHit.begin(), framesThatAreHit.end(), compareFrameViewZOrder); return framesThatAreHit; } KWFrameView *KWFrameViewManager::view(const KWFrame *frame) const { // This is probably the slowest and worst way to do it, mark this for optimalisation! TQValueListConstIterator frames = m_frames.begin(); while(frames != m_frames.end()) { if((*frames)->frame() == frame) return *frames; ++frames; } return 0; } bool KWFrameViewManager::compareFrameViewZOrder(KWFrameView *f1, KWFrameView *f2) { return f1->frame()->zOrder() >= f2->frame()->zOrder(); } TQCursor KWFrameViewManager::mouseCursor( const KoPoint &point, int keyState ) const { KWFrameView *view = 0; TQValueVector framesThatAreHit = framesAt(point); TQValueVector::iterator sortedFrames = framesThatAreHit.begin(); MouseMeaning meaning; while(sortedFrames != framesThatAreHit.end()) { meaning = (*sortedFrames)->mouseMeaning(point, keyState); if(meaning != MEANING_NONE) { view = (*sortedFrames); break; } ++sortedFrames; } if(view == 0) return TQCursor(); // default arrow shape KWFrameSet*frameSet = view->frame()->frameSet(); switch ( meaning ) { case MEANING_NONE: return TQt::ibeamCursor; // default cursor in margins case MEANING_MOUSE_INSIDE: return TQCursor(); // default arrow shape case MEANING_MOUSE_INSIDE_TEXT: return TQt::ibeamCursor; case MEANING_MOUSE_OVER_LINK: return TQt::PointingHandCursor; case MEANING_MOUSE_OVER_FOOTNOTE: return TQt::PointingHandCursor; case MEANING_MOUSE_MOVE: return TQt::sizeAllCursor; case MEANING_MOUSE_SELECT: return KCursor::handCursor(); case MEANING_ACTIVATE_PART: return KCursor::handCursor(); case MEANING_TOPLEFT: case MEANING_BOTTOMRIGHT: return TQt::sizeFDiagCursor; case MEANING_LEFT: case MEANING_RIGHT: return TQt::sizeHorCursor; case MEANING_BOTTOMLEFT: case MEANING_TOPRIGHT: return TQt::sizeBDiagCursor; case MEANING_TOP: case MEANING_BOTTOM: if ( frameSet->isProtectSize() || frameSet->isMainFrameset()) return TQt::forbiddenCursor; return TQt::sizeVerCursor; case MEANING_RESIZE_COLUMN: return TQt::splitHCursor; case MEANING_RESIZE_ROW: return TQt::splitVCursor; case MEANING_SELECT_RANGE: case MEANING_SELECT_COLUMN: case MEANING_SELECT_ROW: case MEANING_FORBIDDEN: return KCursor::handCursor(); } return TQCursor(); // default arrow shape } MouseMeaning KWFrameViewManager::mouseMeaning( const KoPoint &point, int keyState) const { TQValueVector framesThatAreHit = framesAt(point); TQValueVector::iterator sortedFrames = framesThatAreHit.begin(); while(sortedFrames != framesThatAreHit.end()) { MouseMeaning answer = (*sortedFrames)->mouseMeaning(point, keyState); if(answer != MEANING_NONE) { //kdDebug() << "mouseMeaning at " << point << " is " << answer << endl; return answer; } ++sortedFrames; } return MEANING_NONE; } TQValueList KWFrameViewManager::selectedFrames() const { TQValueList selectedFrames; TQValueList::const_iterator frames = m_frames.begin(); for(; frames != m_frames.end(); ++frames ) if( (*frames)->selected() ) selectedFrames.append( *frames ); return selectedFrames; } KWFrameView* KWFrameViewManager::selectedFrame() const { TQValueList::const_iterator frames = m_frames.begin(); for(; frames != m_frames.end(); ++frames ) if( (*frames)->selected() ) return *frames; return 0; } void KWFrameViewManager::showPopup( const KoPoint &point, KWView *view, int keyState, const TQPoint &popupPoint) const { TQValueVector framesThatAreHit = framesAt(point); if(framesThatAreHit.count() == 0) { view->popupMenu("action_popup")->popup(popupPoint); return; } if(keyState == TQt::ControlButton) { // show the border popup of the top most frame. framesThatAreHit[0]->showPopup(framesThatAreHit[0]->frame()->topLeft(), view, popupPoint); return; } TQValueVector::iterator iter = framesThatAreHit.begin(); while(iter != framesThatAreHit.end()) { if( (*iter)->selected() && keyState == TQt::ControlButton ) { (*iter)->showPopup(point, view, popupPoint); return; } ++iter; } framesThatAreHit[0]->showPopup(point, view, popupPoint); } void KWFrameViewManager::selectFrames(const KoPoint &point, int keyState, bool leftClick) { MouseMeaning mm = mouseMeaning(point, keyState); bool multiSelect = mm == MEANING_MOUSE_SELECT || ( keyState & TQt::ControlButton ); SelectionType se = frameOnTop; if(leftClick && multiSelect) se = nextUnselected; KWFrameView *toBeSelected = view(point, se, !multiSelect); //kdDebug() << "KWFrameViewManager::selectFrames" << point << " got: " << toBeSelected << endl; if(toBeSelected == 0 || (keyState & TQt::ControlButton) == 0 || ( keyState & TQt::ShiftButton ) && !(leftClick && (mm == MEANING_TOPLEFT || mm == MEANING_TOPRIGHT || mm == MEANING_TOP || mm == MEANING_LEFT || mm == MEANING_RIGHT || mm == MEANING_MOUSE_MOVE || mm == MEANING_BOTTOMLEFT || mm == MEANING_BOTTOM || mm == MEANING_BOTTOMRIGHT))) { // unselect all for(TQValueListConstIterator frames = m_frames.begin(); frames != m_frames.end(); ++frames) { (*frames)->setSelected(false); } } if(toBeSelected == 0) return; toBeSelected->setSelected(true, mm); slotFrameSelectionChanged(); } // ********** FrameEvent **** */ KWFrameViewManager::FrameEvent::FrameEvent (ActionType action) { m_action = action; } KWFrameViewManager::FrameEvent::FrameEvent (ActionType action, KWFrame *frame) { m_action = action; m_frame = frame; } KWFrameViewManager::FrameEvent::FrameEvent (ActionType action, KWFrameSet *frameSet) { m_action = action; m_frameSet = frameSet; } #include "KWFrameViewManager.moc"