1 /* AbiWord
2  * Copyright (C) 1998-2000 AbiSource, Inc.
3  * Copyright (C) 2001-2003 Hubert Figuiere
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * as published by the Free Software Foundation; either version 2
8  * of the License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18  * 02110-1301 USA.
19  */
20 
21 #include <Cocoa/Cocoa.h>
22 
23 #include "ut_types.h"
24 #include "ut_debugmsg.h"
25 #include "ut_assert.h"
26 #include "xap_ViewListener.h"
27 #include "ap_FrameData.h"
28 #include "xap_CocoaFrame.h"
29 #include "ev_CocoaToolbar.h"
30 #include "xav_View.h"
31 #include "fv_View.h"
32 #include "fl_DocLayout.h"
33 #include "gr_CocoaCairoGraphics.h"
34 #include "xap_Scrollbar_ViewListener.h"
35 #include "ap_CocoaFrame.h"
36 #include "xap_CocoaApp.h"
37 #include "ap_CocoaTopRuler.h"
38 #include "ap_CocoaLeftRuler.h"
39 #include "ap_CocoaStatusBar.h"
40 #include "ap_CocoaViewListener.h"
41 
42 #import "ap_CocoaFrameImpl.h"
43 
44 /*****************************************************************/
45 #define ENSUREP_RF(p)            do { UT_ASSERT(p); if (!p) return false; } while (0)
46 #define ENSUREP(p)		do { UT_ASSERT(p); if (!p) goto Cleanup; } while (0)
47 
48 
setXScrollRange(void)49 void AP_CocoaFrame::setXScrollRange(void)
50 {
51 	GR_Graphics*	pGr = ((AP_FrameData*)m_pData)->m_pG;
52 	AP_CocoaFrameImpl* pFrameImpl = static_cast<AP_CocoaFrameImpl *>(getFrameImpl());
53 	UT_sint32 width = ((AP_FrameData*)m_pData)->m_pDocLayout->getWidth();
54 	NSRect rect = [pFrameImpl->m_docAreaGRView frame];
55 	UT_sint32 visibleWidth = pGr->tlu(lrintf(rect.size.width));
56 	pFrameImpl->_setHVisible(visibleWidth);
57 	UT_DEBUGMSG(("visibleWidth: %d, doc width:%d\n", visibleWidth, width));
58 	if (m_pView == NULL) {
59 		UT_DEBUGMSG(("m_pView is NULL\n"));
60 	}
61 
62 	UT_sint32 newvalue = ((m_pView) ? m_pView->getXScrollOffset() : 0);
63 	UT_sint32 newmax = width - visibleWidth; /* upper - page_size */
64 	if (newmax <= 0)
65 		newmax = 0;
66 	else if (newvalue > newmax)
67 		newvalue = newmax;
68 	UT_DEBUGMSG (("newmax = %d, newvalue = %d\n", newmax, newvalue));
69 	pFrameImpl->_setHScrollMax(newmax);
70 	pFrameImpl->_setHScrollValue(newvalue);
71 
72 	m_pView->sendHorizontalScrollEvent(newvalue, newmax);
73 }
74 
setYScrollRange(void)75 void AP_CocoaFrame::setYScrollRange(void)
76 {
77 	GR_Graphics*	pGr = ((AP_FrameData*)m_pData)->m_pG;
78 	AP_CocoaFrameImpl * pFrameImpl = static_cast<AP_CocoaFrameImpl *>(getFrameImpl());
79 	UT_sint32 height = ((AP_FrameData*)m_pData)->m_pDocLayout->getHeight();
80 	NSRect rect = [pFrameImpl->m_docAreaGRView frame];
81 	UT_sint32 visibleHeight = pGr->tlu(lrintf(rect.size.height));
82 	pFrameImpl->_setVVisible(visibleHeight);
83 	UT_DEBUGMSG(("visibleHeight: %d, doc height:%d\n", visibleHeight, height));
84 	if (m_pView == NULL) {
85 		UT_DEBUGMSG(("m_pView is NULL\n"));
86 	}
87 
88 	UT_sint32 newvalue = ((m_pView) ? m_pView->getYScrollOffset() : 0);
89 	UT_sint32 newmax = height - visibleHeight;	/* upper - page_size */
90 	if (newmax <= 0)
91 		newmax = 0;
92 	else if (newvalue > newmax)
93 		newvalue = newmax;
94 	UT_DEBUGMSG (("newmax = %d, newvalue = %d\n", newmax, newvalue));
95 	pFrameImpl->_setVScrollMax(newmax);
96 	pFrameImpl->_setVScrollValue(newvalue);
97 
98 	// TODO optimize
99 	m_pView->sendVerticalScrollEvent(newvalue, newmax);
100 }
101 
102 
AP_CocoaFrame()103 AP_CocoaFrame::AP_CocoaFrame()
104 	: AP_Frame (new AP_CocoaFrameImpl(this))
105 {
106 	m_pData = NULL;
107 //	static_cast<AP_CocoaFrameImpl *>(m_pFrameImpl)->setShowDocLocked(false);
108 }
109 
AP_CocoaFrame(AP_CocoaFrame * f)110 AP_CocoaFrame::AP_CocoaFrame(AP_CocoaFrame * f)
111 	: AP_Frame(static_cast<AP_Frame *>(f))
112 {
113 	m_pData = NULL;
114 }
115 
~AP_CocoaFrame()116 AP_CocoaFrame::~AP_CocoaFrame()
117 {
118 	killFrameData();
119 }
120 
initialize(XAP_FrameMode)121 bool AP_CocoaFrame::initialize(XAP_FrameMode /*frameMode*/)
122 {
123 	AP_CocoaFrameImpl* pFrameImpl = static_cast<AP_CocoaFrameImpl *>(getFrameImpl());
124 	UT_DEBUGMSG(("AP_CocoaFrame::initialize\n"));
125 	if (!initFrameData())
126 		return false;
127 
128 	if (!XAP_Frame::initialize(AP_PREF_KEY_KeyBindings,AP_PREF_DEFAULT_KeyBindings,
129 								   AP_PREF_KEY_MenuLayout, AP_PREF_DEFAULT_MenuLayout,
130 								   AP_PREF_KEY_StringSet, AP_PREF_DEFAULT_StringSet,
131 								   AP_PREF_KEY_ToolbarLayouts, AP_PREF_DEFAULT_ToolbarLayouts,
132 								   AP_PREF_KEY_StringSet, AP_PREF_DEFAULT_StringSet))
133 		return false;
134 
135 	pFrameImpl->_createTopLevelWindow();
136 //	gtk_widget_show(m_wTopLevelWindow);
137 	if(getFrameMode() == XAP_NormalFrame)
138 	{
139 		// needs to be shown so that the following functions work
140 		// TODO: get rid of cursed flicker caused by initially
141 		// TODO: showing these and then hiding them (esp.
142 		// TODO: noticable in the gnome build with a toolbar disabled)
143 		pFrameImpl->_showOrHideToolbars();
144 		pFrameImpl->_showOrHideStatusbar();
145 	}
146 	// pFrameImpl->_show(); // defer this
147 
148 	return true;
149 }
150 
151 
152 
153 
154 /*****************************************************************/
155 
cloneFrame()156 XAP_Frame * AP_CocoaFrame::cloneFrame()
157 {
158 	AP_CocoaFrame * pClone = new AP_CocoaFrame(this);
159 	ENSUREP(pClone);
160 	return static_cast<XAP_Frame *> (pClone);
161 
162 Cleanup:
163 	// clean up anything we created here
164 	if (pClone)
165 	{
166 		XAP_App::getApp()->forgetFrame(pClone);
167 		delete pClone;
168 	}
169 
170 	return NULL;
171 }
172 
173 
_scrollFuncY(void * pData,UT_sint32 yoff,UT_sint32)174 void AP_CocoaFrame::_scrollFuncY(void * pData, UT_sint32 yoff, UT_sint32 /*yrange*/)
175 {
176 	// this is a static callback function and doesn't have a 'this' pointer.
177 	AP_CocoaFrame * pCocoaFrame = static_cast<AP_CocoaFrame *>(pData);
178 	AP_CocoaFrameImpl* pFrameImpl = static_cast<AP_CocoaFrameImpl*>(pCocoaFrame->getFrameImpl());
179 	AV_View * pView = pCocoaFrame->getCurrentView();
180 
181 	if (pFrameImpl->_getVScrollMin() > yoff) {
182 		yoff = pFrameImpl->_getVScrollMin();
183 	}
184 	if (pFrameImpl->_getVScrollMax() < yoff) {
185 		yoff = pFrameImpl->_getVScrollMax();
186 	}
187 	pFrameImpl->_setVScrollValue(yoff);
188 
189 	pView->setYScrollOffset(yoff);
190 }
191 
_scrollFuncX(void * pData,UT_sint32 xoff,UT_sint32)192 void AP_CocoaFrame::_scrollFuncX(void * pData, UT_sint32 xoff, UT_sint32 /*xrange*/)
193 {
194 	// this is a static callback function and doesn't have a 'this' pointer.
195 
196 	AP_CocoaFrame * pCocoaFrame = static_cast<AP_CocoaFrame *>(pData);
197 	AP_CocoaFrameImpl* pFrameImpl = static_cast<AP_CocoaFrameImpl*>(pCocoaFrame->getFrameImpl());
198 	AV_View * pView = pCocoaFrame->getCurrentView();
199 
200 	if (pFrameImpl->_getHScrollMin() > xoff) {
201 		xoff = pFrameImpl->_getHScrollMin();
202 	}
203 	if (pFrameImpl->_getHScrollMax() < xoff) {
204 		xoff = pFrameImpl->_getHScrollMax();
205 	}
206 	pFrameImpl->_setHScrollValue(xoff);
207 
208 	pView->setXScrollOffset(xoff);
209 }
210 
211 
212 
translateDocumentToScreen(UT_sint32 &,UT_sint32 &)213 void AP_CocoaFrame::translateDocumentToScreen(UT_sint32 & /*x*/, UT_sint32 & /*y*/)
214 {
215 	// translate the given document mouse coordinates into absolute screen coordinates.
216 	UT_ASSERT (UT_NOT_IMPLEMENTED);
217 #if 0
218 	Window child;
219 	gint tx;
220 	gint ty;
221 
222 	GdkWindowPrivate * priv = (GdkWindowPrivate*) m_dArea->window;
223 	if (!priv->destroyed)
224 		XTranslateCoordinates (priv->xdisplay, priv->xwindow, gdk_root_window, x, y, &tx, &ty, &child);
225 
226 	x = tx;
227 	y = ty;
228 #endif
229 }
230 
231 
setStatusMessage(const char * szMsg)232 void AP_CocoaFrame::setStatusMessage(const char * szMsg)
233 {
234 	((AP_FrameData *)m_pData)->m_pStatusBar->setStatusMessage(szMsg);
235 }
236 
237 
toggleTopRuler(bool bRulerOn)238 void AP_CocoaFrame::toggleTopRuler(bool bRulerOn)
239 {
240 	AP_FrameData *pFrameData = static_cast<AP_FrameData *>(getFrameData());
241 	UT_ASSERT(pFrameData);
242 
243 	AP_CocoaTopRuler * pCocoaTopRuler = NULL;
244 
245 	UT_DEBUGMSG(("AP_CocoaFrame::toggleTopRuler %d, %p\n",
246 		     bRulerOn, pFrameData->m_pTopRuler));
247 	if (bRulerOn) {
248 		AP_TopRuler * pTop = pFrameData->m_pTopRuler;
249 		if(pTop) {
250 			delete pTop;
251 		}
252 
253 		pCocoaTopRuler = new AP_CocoaTopRuler(this);
254 		UT_ASSERT(pCocoaTopRuler);
255 
256 		// get the width from the left ruler and stuff it into the
257 		// top ruler.
258 
259 		if (static_cast<AP_FrameData*>(m_pData)->m_pLeftRuler) {
260 			pCocoaTopRuler->setOffsetLeftRuler(((AP_FrameData*)m_pData)->m_pLeftRuler->getWidth());
261 		}
262 		else {
263 			pCocoaTopRuler->setOffsetLeftRuler(0);
264 		}
265 
266 		// attach everything
267 		static_cast<AP_CocoaFrameImpl *>(getFrameImpl())->_showTopRulerNSView();
268 		FV_View * pView = static_cast<FV_View *>(m_pView);
269 		UT_uint32 iZoom = pView->getGraphics()->getZoomPercentage();
270 		static_cast<AP_TopRuler *>(pCocoaTopRuler)->setView(m_pView,iZoom);
271 	}
272 	else {
273 		static_cast<AP_CocoaFrameImpl *>(getFrameImpl())->_hideTopRulerNSView();
274 		DELETEP(((AP_FrameData*)m_pData)->m_pTopRuler);
275 		static_cast<FV_View *>(m_pView)->setTopRuler(NULL);
276 	}
277 	static_cast<AP_FrameData*>(m_pData)->m_pTopRuler = pCocoaTopRuler;
278 }
279 
toggleLeftRuler(bool bRulerOn)280 void AP_CocoaFrame::toggleLeftRuler(bool bRulerOn)
281 {
282 	AP_FrameData *pFrameData = (AP_FrameData *)getFrameData();
283 	UT_ASSERT(pFrameData);
284 
285 	UT_DEBUGMSG(("AP_CocoaFrame::toggleLeftRuler %d, %p\n", bRulerOn, pFrameData->m_pLeftRuler));
286 
287 	if (bRulerOn) {
288 		AP_CocoaLeftRuler* pCocoaLeftRuler;
289 		FV_View * pView = static_cast<FV_View *>(m_pView);
290 		UT_uint32 iZoom = pView->getGraphics()->getZoomPercentage();
291 
292 		pCocoaLeftRuler = new AP_CocoaLeftRuler(this);
293 		UT_ASSERT(pCocoaLeftRuler);
294 		pFrameData->m_pLeftRuler = pCocoaLeftRuler;
295 
296 		static_cast<AP_CocoaFrameImpl *>(getFrameImpl())->_showLeftRulerNSView();
297 		static_cast<AP_LeftRuler *>(pCocoaLeftRuler)->setView(m_pView, iZoom);
298 		setYScrollRange ();
299 	}
300 	else  {
301 		if (pFrameData->m_pLeftRuler) {
302 			DELETEP(pFrameData->m_pLeftRuler);
303 			static_cast<AP_CocoaFrameImpl *>(getFrameImpl())->_hideLeftRulerNSView();
304 			static_cast<FV_View *>(m_pView)->setLeftRuler(NULL);
305 		}
306 		else {
307 			UT_DEBUGMSG(("Left Ruler already hidden\n"));
308 		}
309 	}
310 
311 }
312 
toggleRuler(bool bRulerOn)313 void AP_CocoaFrame::toggleRuler(bool bRulerOn)
314 {
315 	AP_FrameData *pFrameData = (AP_FrameData *)getFrameData();
316 	UT_ASSERT(pFrameData);
317 
318 	toggleTopRuler(bRulerOn);
319 	toggleLeftRuler(bRulerOn && (pFrameData->m_pViewMode == VIEW_PRINT));
320 
321 	[(static_cast<AP_CocoaFrameImpl *>(getFrameImpl())->m_docAreaGRView) setNeedsDisplay:YES];
322 }
323 
toggleBar(UT_uint32 iBarNb,bool bBarOn)324 void AP_CocoaFrame::toggleBar(UT_uint32 iBarNb, bool bBarOn)
325 {
326 	UT_DEBUGMSG(("AP_CocoaFrame::toggleBar %d, %d\n", iBarNb, bBarOn));
327 
328 	AP_FrameData *pFrameData = static_cast<AP_FrameData *> (getFrameData());
329 	UT_ASSERT(pFrameData);
330 
331 	if (bBarOn) {
332 		pFrameData->m_pToolbar[iBarNb]->show();
333 	}
334 	else {	// turning toolbar off
335 		pFrameData->m_pToolbar[iBarNb]->hide();
336 	}
337 }
338 
toggleStatusBar(bool bStatusBarOn)339 void AP_CocoaFrame::toggleStatusBar(bool bStatusBarOn)
340 {
341 	UT_DEBUGMSG(("AP_CocoaFrame::toggleStatusBar %d\n", bStatusBarOn));
342 
343 	AP_FrameData *pFrameData = static_cast<AP_FrameData *> (getFrameData());
344 	UT_ASSERT(pFrameData);
345 
346 	if (bStatusBarOn) {
347 		pFrameData->m_pStatusBar->show();
348 	}
349 	else {	// turning status bar off
350 		pFrameData->m_pStatusBar->hide();
351 	}
352 }
353 
_createScrollBarListeners(AV_View * pView,AV_ScrollObj * & pScrollObj,ap_ViewListener * & pViewListener,ap_Scrollbar_ViewListener * & pScrollbarViewListener,AV_ListenerId & lid,AV_ListenerId & lidScrollbarViewListener)354 bool AP_CocoaFrame::_createScrollBarListeners(AV_View * pView, AV_ScrollObj *& pScrollObj,
355 					     ap_ViewListener *& pViewListener, ap_Scrollbar_ViewListener *& pScrollbarViewListener,
356 					     AV_ListenerId &lid, AV_ListenerId &lidScrollbarViewListener)
357 {
358 	// The "AV_ScrollObj pScrollObj" receives
359 	// send{Vertical,Horizontal}ScrollEvents
360 	// from both the scroll-related edit methods
361 	// and from the UI callbacks.
362 	//
363 	// The "ap_ViewListener pViewListener" receives
364 	// change notifications as the document changes.
365 	// This ViewListener is responsible for keeping
366 	// the title-bar up to date (primarily title
367 	// changes, dirty indicator, and window number).
368 	// ON UNIX ONLY: we subclass this with ap_UnixViewListener
369 	// ON UNIX ONLY: so that we can deal with X-Selections.
370 	//
371 	// The "ap_Scrollbar_ViewListener pScrollbarViewListener"
372 	// receives change notifications as the doucment changes.
373 	// This ViewListener is responsible for recalibrating the
374 	// scrollbars as pages are added/removed from the document.
375 	//
376 	// Each Toolbar will also get a ViewListener so that
377 	// it can update toggle buttons, and other state-indicating
378 	// controls on it.
379 	//
380 	// TODO we ***really*** need to re-do the whole scrollbar thing.
381 	// TODO we have an addScrollListener() using an m_pScrollObj
382 	// TODO and a View-Listener, and a bunch of other widget stuff.
383 	// TODO and its very confusing.
384 
385 	pScrollObj = new AV_ScrollObj(this,_scrollFuncX,_scrollFuncY);
386 	ENSUREP_RF(pScrollObj);
387 
388 	pViewListener = new ap_CocoaViewListener(this);
389 	ENSUREP_RF(pViewListener);
390 	pScrollbarViewListener = new ap_Scrollbar_ViewListener(this,pView);
391 	ENSUREP_RF(pScrollbarViewListener);
392 
393 	if (!pView->addListener(static_cast<AV_Listener *>(pViewListener),&lid))
394 		return false;
395 	if (!pView->addListener(static_cast<AV_Listener *>(pScrollbarViewListener),
396 							&lidScrollbarViewListener))
397 		return false;
398 
399 	return true;
400 }
401 
402 
_getDocumentAreaWidth()403 UT_sint32 AP_CocoaFrame::_getDocumentAreaWidth()
404 {
405 	return (UT_sint32)[static_cast<AP_CocoaFrameImpl *>(getFrameImpl())->m_docAreaGRView frame].size.width;
406 }
407 
_getDocumentAreaHeight()408 UT_sint32 AP_CocoaFrame::_getDocumentAreaHeight()
409 {
410 	return (UT_sint32)[static_cast<AP_CocoaFrameImpl *>(getFrameImpl())->m_docAreaGRView frame].size.height;
411 }
412 
_createViewGraphics(GR_Graphics * & pG,UT_uint32 iZoom)413 bool AP_CocoaFrame::_createViewGraphics(GR_Graphics *& pG, UT_uint32 iZoom)
414 {
415 
416 	static_cast<AP_CocoaFrameImpl*>(getFrameImpl())->_createDocView(pG);
417 	ENSUREP_RF(pG);
418 	pG->setZoomPercentage(iZoom);
419 
420 	return true;
421 }
422 
_setViewFocus(AV_View *)423 void AP_CocoaFrame::_setViewFocus(AV_View * /*pView*/)
424 {
425 	AP_CocoaFrameImpl * pFrameImpl = static_cast<AP_CocoaFrameImpl *>(getFrameImpl());
426 	pFrameImpl->giveFocus();
427 }
428 
_bindToolbars(AV_View * pView)429 void AP_CocoaFrame::_bindToolbars(AV_View *pView)
430 {
431 	static_cast<AP_CocoaFrameImpl *>(getFrameImpl())->_bindToolbars(pView);
432 }
433 
434