1 /* AbiSource Application Framework
2 * Copyright (C) 1998-2000 AbiSource, Inc.
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17 * 02110-1301 USA.
18 */
19
20
21 #include "ut_debugmsg.h"
22
23 #include "xav_View.h"
24 #include "xav_Listener.h"
25
26 #include "xap_Frame.h"
27 #include "xap_App.h"
28
AV_View(XAP_App * pApp,void * pParentData)29 AV_View::AV_View(XAP_App * pApp, void* pParentData)
30 : m_pApp(pApp),
31 m_pParentData(pParentData),
32 m_xScrollOffset(0),
33 m_yScrollOffset(0),
34 m_focus(AV_FOCUS_NONE),
35 m_iTick(0),
36 m_bInsertMode(true),
37 m_VisualSelectionActive(false),
38 m_bIsLayoutFilling(false),
39 m_iWindowHeight(0),
40 m_iWindowWidth(0),
41 m_dOneTDU(0),
42 m_bCouldBeActive(true),
43 m_bConfigureChanged(false)
44 {
45 }
46
~AV_View()47 AV_View::~AV_View()
48 {
49 UT_DEBUGMSG(("Deleting view %p \n",this));
50 }
51
getParentData() const52 void* AV_View::getParentData() const
53 {
54 return m_pParentData;
55 }
56
addListener(AV_Listener * pListener,AV_ListenerId * pListenerId)57 bool AV_View::addListener(AV_Listener * pListener,
58 AV_ListenerId * pListenerId)
59 {
60 UT_sint32 kLimit = m_vecListeners.getItemCount();
61 UT_sint32 k;
62
63 // see if we can recycle a cell in the vector.
64
65 for (k=0; k<kLimit; k++)
66 if (m_vecListeners.getNthItem(k) == 0)
67 {
68 static_cast<void>(m_vecListeners.setNthItem(k,pListener,NULL));
69 goto ClaimThisK;
70 }
71
72 // otherwise, extend the vector for it.
73
74 if (m_vecListeners.addItem(pListener,&k) != 0)
75 {
76 return false; // could not add item to vector
77 }
78
79 ClaimThisK:
80
81 // give our vector index back to the caller as a "Listener Id".
82
83 *pListenerId = k;
84
85 UT_DEBUGMSG(("Adding listener %p type %d id %d \n",pListener,pListener->getType(),k));
86 return true;
87 }
88
removeListener(AV_ListenerId listenerId)89 bool AV_View::removeListener(AV_ListenerId listenerId)
90 {
91 if (listenerId == (AV_ListenerId) -1)
92 return false;
93
94 return (m_vecListeners.setNthItem(listenerId,NULL,NULL) == 0);
95 }
96
notifyListeners(const AV_ChangeMask hint,void * pPrivateData)97 bool AV_View::notifyListeners(const AV_ChangeMask hint, void * pPrivateData)
98 {
99 /*
100 App-specific logic calls this virtual method when relevant portions of
101 the view state *may* have changed. (That's why it's called a hint.)
102
103 This base class implementation doesn't do any filtering of those
104 hints, it just broadcasts those hints to all listeners.
105
106 Subclasses are encouraged to improve the quality of those hints by
107 filtering out mask bits which haven't *actually* changed since the
108 last notification. To do so, they would
109
110 - copy the hint (it's passed as a const),
111 - clear any irrelevant bits, and
112 - call this implementation on the way out
113
114 Good hinting logic is app-specific, and non-trivial to tune, but it's
115 worth doing, because it helps minimizes flicker for things like
116 toolbar button state.
117 */
118 if(!isDocumentPresent())
119 {
120 return false;
121 }
122 if((hint != AV_CHG_FOCUS) && (hint != AV_CHG_MOUSEPOS) )
123 {
124 xxx_UT_DEBUGMSG(("hint mask = %x \n",hint));
125 m_iTick++;
126 }
127 // make sure there's something left
128
129 if (hint == AV_CHG_NONE)
130 {
131 return false;
132 }
133
134 // notify listeners of a change.
135
136 AV_ListenerId lid;
137 AV_ListenerId lidCount = m_vecListeners.getItemCount();
138
139 // for each listener in our vector, we send a notification.
140 // we step over null listners (for listeners which have been
141 // removed (views that went away)).
142 bool bIsLayoutFilling = isLayoutFilling();
143 for (lid=0; lid<lidCount; lid++)
144 {
145 AV_Listener * pListener = static_cast<AV_Listener *>(m_vecListeners.getNthItem(lid));
146 if(pListener && (!bIsLayoutFilling
147 || (pListener->getType()== AV_LISTENER_STATUSBAR)
148 || (pListener->getType()== AV_LISTENER_SCROLLBAR)))
149 {
150 pListener->notify(this,hint);
151 }
152 }
153 getApp()->notifyListeners(this,hint,pPrivateData);
154 return true;
155 }
156
setActivityMask(bool bActive)157 void AV_View:: setActivityMask(bool bActive)
158 {
159 m_bCouldBeActive = bActive;
160 }
161
getTick(void) const162 UT_uint32 AV_View::getTick(void) const
163 {
164 return m_iTick;
165 }
166
incTick(void)167 void AV_View::incTick(void)
168 {
169 m_iTick++;
170 }
171
setInsertMode(bool bInsert)172 void AV_View::setInsertMode(bool bInsert)
173 {
174 m_bInsertMode = bInsert;
175
176 notifyListeners(AV_CHG_INSERTMODE);
177 }
178
179 /*! the input is in device units, but internal storage is in logical units
180 */
setWindowSize(UT_sint32 width,UT_sint32 height)181 void AV_View::setWindowSize(UT_sint32 width, UT_sint32 height)
182 {
183 m_iWindowWidth = getGraphics()->tlu(width);
184 m_iWindowHeight = getGraphics()->tlu(height);
185 m_dOneTDU = getGraphics()->tduD(1.0);
186
187 notifyListeners(AV_CHG_WINDOWSIZE);
188 }
189
addScrollListener(AV_ScrollObj * pObj)190 void AV_View::addScrollListener(AV_ScrollObj* pObj)
191 {
192 UT_sint32 count = m_scrollListeners.getItemCount();
193
194 for (UT_sint32 i = count-1; i >=0; i--)
195 {
196 AV_ScrollObj* obj = m_scrollListeners.getNthItem(i);
197
198 if (obj == pObj)
199 {
200 UT_DEBUGMSG(("Extra scroll object attempted attachment \n"));
201 // UT_ASSERT_HARMLESS(UT_SHOULD_NOT_HAPPEN);
202 return;
203 }
204
205 }
206 m_scrollListeners.addItem(pObj);
207 }
208
removeScrollListener(AV_ScrollObj * pObj)209 void AV_View::removeScrollListener(AV_ScrollObj* pObj)
210 {
211 UT_sint32 count = m_scrollListeners.getItemCount();
212
213 for (UT_sint32 i = count-1; i >=0; i--)
214 {
215 AV_ScrollObj* obj = m_scrollListeners.getNthItem(i);
216
217 if (obj == pObj)
218 {
219 UT_DEBUGMSG(("Removing scroll listener %p in av_view %p \n",obj,this));
220 m_scrollListeners.deleteNthItem(i);
221 }
222 }
223 }
224
225 /*! the input is in layout units
226 */
sendVerticalScrollEvent(UT_sint32 yoff,UT_sint32 ylimit)227 void AV_View::sendVerticalScrollEvent(UT_sint32 yoff, UT_sint32 ylimit)
228 {
229 if(getWindowHeight() < getGraphics()->tlu(20))
230 return;
231 UT_sint32 count = m_scrollListeners.getItemCount();
232
233 for (UT_sint32 i = 0; i < count; i++)
234 {
235 AV_ScrollObj* pObj = m_scrollListeners.getNthItem(i);
236 pObj->m_pfnY(pObj->m_pData, yoff, ylimit);
237 }
238 }
239
240 /*! the input is in layout units
241 */
sendHorizontalScrollEvent(UT_sint32 xoff,UT_sint32 xlimit)242 void AV_View::sendHorizontalScrollEvent(UT_sint32 xoff, UT_sint32 xlimit)
243 {
244 if(getWindowHeight() < getGraphics()->tlu(20))
245 return;
246
247 UT_sint32 count = m_scrollListeners.getItemCount();
248
249 for (UT_sint32 i = 0; i < count; i++)
250 {
251 AV_ScrollObj* pObj = m_scrollListeners.getNthItem(i);
252
253 pObj->m_pfnX(pObj->m_pData, xoff, xlimit);
254 }
255 }
256
getWindowHeight(void) const257 UT_sint32 AV_View::getWindowHeight(void) const
258 {
259 return static_cast<UT_sint32>(m_iWindowHeight * m_dOneTDU /
260 getGraphics()->tduD(1.0));
261 }
262
getWindowWidth(void) const263 UT_sint32 AV_View::getWindowWidth(void) const
264 {
265 return static_cast<UT_sint32>(m_iWindowWidth * m_dOneTDU /
266 getGraphics()->tduD(1.0));
267 }
268