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