/* AbiWord
 * Copyright (C) 1998-2000 AbiSource, Inc.
 * 
 * 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 "ut_types.h"
#include "ut_debugmsg.h"
#include "ut_assert.h"
#include "xap_ViewListener.h"
#include "ap_FrameData.h"
#include "xap_QNXFrame.h"
#include "ev_QNXToolbar.h"
#include "xav_View.h"
#include "xad_Document.h"
#include "fv_View.h"
#include "fl_DocLayout.h"
#include "pd_Document.h"
#include "gr_QNXGraphics.h"
#include "xap_Scrollbar_ViewListener.h"
#include "ap_QNXFrame.h"
#include "xap_QNXApp.h"
#include "ap_QNXTopRuler.h"
#include "ap_QNXLeftRuler.h"
#include "ap_QNXStatusBar.h"
#include "ap_QNXViewListener.h"
#include "ut_Xpm2Bitmap.h"

#include "ut_qnxHelper.h"

#ifdef ABISOURCE_LICENSED_TRADEMARKS
#include "abiword_48_tm.xpm"
#else
#include "abiword_48.xpm"
#endif


#if !defined(Pt_ARG_SCROLLBAR_POSITION)
#define Pt_ARG_SCROLLBAR_POSITION Pt_ARG_SCROLL_POSITION
#endif

/*****************************************************************/

#define REPLACEP(p,q)	do { if (p) delete p; p = q; } while (0)
#define ENSUREP(p)		do { UT_ASSERT(p); if (!p) goto Cleanup; } while (0)

/*****************************************************************/

void AP_QNXFrame::setZoomPercentage(UT_uint32 iZoom)
{
	_showDocument(iZoom);
}

UT_uint32 AP_QNXFrame::getZoomPercentage(void)
{
	return ((AP_FrameData*)m_pData)->m_pG->getZoomPercentage();
}

UT_Error AP_QNXFrame::_showDocument(UT_uint32 iZoom)
{
	UT_DEBUGMSG(("Frame: _showDocument \n"));

	if (!m_pDoc)
	{
		UT_DEBUGMSG(("Can't show a non-existent document\n"));
		return UT_IE_FILENOTFOUND;
	}

	if (!((AP_FrameData*)m_pData))
	{
		UT_ASSERT(UT_SHOULD_NOT_HAPPEN);
		return UT_IE_IMPORTERROR;
	}

	GR_QNXGraphics * pG = NULL;
	FL_DocLayout * pDocLayout = NULL;
	AV_View * pView = NULL;
	AV_ScrollObj * pScrollObj = NULL;
	ap_ViewListener * pViewListener = NULL;
	AD_Document * pOldDoc = NULL;
	ap_Scrollbar_ViewListener * pScrollbarViewListener = NULL;
	AV_ListenerId lid;
	AV_ListenerId lidScrollbarViewListener;
	UT_uint32 nrToolbars;
	UT_uint32 point = 0;
	UT_uint32 k = 0;

	pG = new GR_QNXGraphics(m_wTopLevelWindow, m_dArea, getApp());
	ENSUREP(pG);
	pG->setZoomPercentage(iZoom);
	
	pDocLayout = new FL_DocLayout((PD_Document *)(m_pDoc), pG);
	ENSUREP(pDocLayout);
  
	/*TF DIFF: The unix version has this commented out???*/
	//pDocLayout->formatAll();

	pView = new FV_View(getApp(), this, pDocLayout);
	if (m_pView != NULL)
	{
		point = ((FV_View *) m_pView)->getPoint();
//		pView->setFocus(m_pView->getFocus());		//Keep the same focus policy
	}
	ENSUREP(pView);

	// The "AV_ScrollObj pScrollObj" receives
	// send{Vertical,Horizontal}ScrollEvents
	// from both the scroll-related edit methods
	// and from the UI callbacks.
	// 
	// The "ap_ViewListener pViewListener" receives
	// change notifications as the document changes.
	// This ViewListener is responsible for keeping
	// the title-bar up to date (primarily title
	// changes, dirty indicator, and window number).
	//
	// The "ap_Scrollbar_ViewListener pScrollbarViewListener"
	// receives change notifications as the doucment changes.
	// This ViewListener is responsible for recalibrating the
	// scrollbars as pages are added/removed from the document.
	//
	// Each Toolbar will also get a ViewListener so that
	// it can update toggle buttons, and other state-indicating
	// controls on it.
	//
	// TODO we ***really*** need to re-do the whole scrollbar thing.
	// TODO we have an addScrollListener() using an m_pScrollObj
	// TODO and a View-Listener, and a bunch of other widget stuff.
	// TODO and its very confusing.
	pScrollObj = new AV_ScrollObj(this,_scrollFuncX,_scrollFuncY);
	ENSUREP(pScrollObj);
	pViewListener = new ap_QNXViewListener(this);
	ENSUREP(pViewListener);
	pScrollbarViewListener = new ap_Scrollbar_ViewListener(this,pView);
	ENSUREP(pScrollbarViewListener);

	if (!pView->addListener((AV_Listener *)pViewListener,&lid))
		goto Cleanup;

	if (!pView->addListener((AV_Listener *)pScrollbarViewListener,
							&lidScrollbarViewListener))
		goto Cleanup;

	nrToolbars = m_vecToolbarLayoutNames.getItemCount();
	for (k=0; k < nrToolbars; k++)
	{
		// TODO Toolbars are a frame-level item, but a view-listener is
		// TODO a view-level item.  I've bound the toolbar-view-listeners
		// TODO to the current view within this frame and have code in the
		// TODO toolbar to allow the view-listener to be rebound to a different
		// TODO view.  in the future, when we have support for multiple views
		// TODO in the frame (think splitter windows), we will need to have
		// TODO a loop like this to help change the focus when the current
		// TODO view changes.
		
		EV_QNXToolbar * pQNXToolbar = (EV_QNXToolbar *)m_vecToolbars.getNthItem(k);
		pQNXToolbar->bindListenerToView(pView);
	}

	/****************************************************************
	*****************************************************************
	** If we reach this point, everything for the new document has
	** been created.  We can now safely replace the various fields
	** within the structure.  Nothing below this point should fail.
	*****************************************************************
	****************************************************************/
	
	// switch to new view, cleaning up previous settings
	if (((AP_FrameData*)m_pData)->m_pDocLayout)
	{
		pOldDoc = ((AP_FrameData*)m_pData)->m_pDocLayout->getDocument();
	}

	REPLACEP(((AP_FrameData*)m_pData)->m_pG, pG);
	REPLACEP(((AP_FrameData*)m_pData)->m_pDocLayout, pDocLayout);
	if (pOldDoc != m_pDoc)
	{
		UNREFP(pOldDoc);
	}
	REPLACEP(m_pView, pView);
	REPLACEP(m_pScrollObj, pScrollObj);
	REPLACEP(m_pViewListener, pViewListener);
	m_lid = lid;
	REPLACEP(m_pScrollbarViewListener,pScrollbarViewListener);
	m_lidScrollbarViewListener = lidScrollbarViewListener;

	m_pView->addScrollListener(m_pScrollObj);

	// Associate the new view with the existing TopRuler, LeftRuler.
	// Because of the binding to the actual on-screen widgets we do
	// not destroy and recreate the TopRuler, LeftRuler when we change
	// views, like we do for all the other objects.  We also do not
	// allocate the TopRuler, LeftRuler  here; that is done as the
	// frame is created.
	/*TF DIFF: QNX version checks the 
		  if ( ((AP_FrameData*)m_pData)->m_bShowRuler )
	  before showing the rulers.
	*/
	if ( ((AP_FrameData*)m_pData)->m_bShowRuler )
	{
	  if ( ((AP_FrameData*)m_pData)->m_pTopRuler )
	    ((AP_FrameData*)m_pData)->m_pTopRuler->setView(pView, iZoom);
	  if ( ((AP_FrameData*)m_pData)->m_pLeftRuler )
		((AP_FrameData*)m_pData)->m_pLeftRuler->setView(pView, iZoom);
	}

	if ( ((AP_FrameData*)m_pData)->m_pStatusBar )
	  ((AP_FrameData*)m_pData)->m_pStatusBar->setView(pView);
    ((FV_View *) m_pView)->setShowPara(((AP_FrameData*)m_pData)->m_bShowPara);

	pView->setInsertMode(((AP_FrameData*)m_pData)->m_bInsertMode);
	
	unsigned short w, h;
	UT_QNXGetWidgetArea(m_dArea, NULL, NULL, &w, &h);
	UT_DEBUGMSG(("FRAME: Setting window to %d/%d ", w,h));
	m_pView->setWindowSize(w, h);

	setXScrollRange();
	setYScrollRange();
	updateTitle();

	pDocLayout->fillLayouts();
	if (m_pView != NULL)
	{
		// we cannot just set the insertion position to that of the previous
		// view, since the new document could be shorter or completely
		// different from the previous one (see bug 2615)
		// Instead we have to test that the original position is within
		// the editable bounds, and if not, we will set the point
		// to the end of the document (i.e., if reloading an earlier
		// version of the same document we try to get the point as near
		// the users editing position as possible
		point = ((FV_View *) m_pView)->getPoint();
		PT_DocPosition posEOD;
		static_cast<FV_View *>(pView)->getEditableBounds(true, posEOD, false);
		if(point > posEOD)
			point = posEOD;
	}
	if (point != 0)
		((FV_View *) m_pView)->moveInsPtTo(point);
	m_pView->draw();

	/*TF DIFF: QNX code to control the ruler looks like:
	  if ( ((AP_FrameData*)m_pData)->m_bShowRuler  ) {
	      if ( ((AP_FrameData*)m_pData)->m_pTopRuler )
		...
	*/
	if ( ((AP_FrameData*)m_pData)->m_bShowRuler  ) 
	{
		if ( ((AP_FrameData*)m_pData)->m_pTopRuler )
			((AP_FrameData*)m_pData)->m_pTopRuler->draw(NULL);

		if ( ((AP_FrameData*)m_pData)->m_pLeftRuler )
			((AP_FrameData*)m_pData)->m_pLeftRuler->draw(NULL);
	}

	if(PtWidgetIsRealized(m_wStatusBar) != 0) {
		((AP_FrameData*)m_pData)->m_pStatusBar->draw();
	}

	PtContainerGiveFocus(m_dArea, NULL);

	return UT_OK;

Cleanup:
	// clean up anything we created here
	DELETEP(pG);
	DELETEP(pDocLayout);
	DELETEP(pView);
	DELETEP(pViewListener);
	DELETEP(pScrollObj);
	DELETEP(pScrollbarViewListener);

	// change back to prior document
	UNREFP(m_pDoc);
	m_pDoc = ((AP_FrameData*)m_pData)->m_pDocLayout->getDocument();

	UT_DEBUGMSG(("Frame: return from _showDocument false \n"));
	return UT_IE_ADDLISTENERERROR;
}

/*
 This function is called whenever we are re-sized to
 re-calculate the size/extent of the scroll bars.
 Once the size is calculated, it should send a new
 position event off.
*/
void AP_QNXFrame::setXScrollRange(void)
{
	int width = ((AP_FrameData*)m_pData)->m_pDocLayout->getWidth();
	int n, windowWidth;
	PtArg_t args[6];

	unsigned short tmp;
	UT_QNXGetWidgetArea(m_dArea, NULL, NULL, &tmp, NULL);
	windowWidth = tmp;

	int newvalue = ((m_pView) ? m_pView->getXScrollOffset() : 0);
	int newmax = width - windowWidth; /* upper - page_size */
	if (newmax <= 0)
	{
	newmax=0;
	newvalue=0;
	}
	if (newvalue > newmax)
		newvalue = newmax;

	float slidersize;
	slidersize = (float)windowWidth / (float)newmax; 
	slidersize *= (float)windowWidth;

	n=0;
	PtSetArg(&args[n++], Pt_ARG_MAXIMUM, newmax, 0); 
	PtSetArg(&args[n++], Pt_ARG_INCREMENT, 20, 0); 
	PtSetArg(&args[n++], Pt_ARG_PAGE_INCREMENT, windowWidth, 0); 
	PtSetArg(&args[n++], Pt_ARG_SCROLLBAR_POSITION, newvalue, 0); 
	/* PtSetArg(&args[n++], Pt_ARG_SLIDER_SIZE, (int)slidersize, 0); */
	PtSetResources(m_hScroll, n, args);
	UT_DEBUGMSG(("X SLIDER SIZE CHANGE TO %f (max %d) ", slidersize, newmax));

	/*
	bool bDifferentPosition = (newvalue != (int)m_pHadj->value);
	bool bDifferentLimits = ((width-windowWidth) != (m_pHadj->upper-m_pHadj->page_size));
	*/
	bool bDifferentPosition = 1;
	bool bDifferentLimits = 1;

	//printf("Set X limits to %d -[%d]- %d \n", 0, newvalue, newmax);
	
	if (m_pView && (bDifferentPosition || bDifferentLimits)) {
		m_pView->sendHorizontalScrollEvent(newvalue, (long) width-windowWidth);
	}
}

void AP_QNXFrame::setYScrollRange(void)
{
	int height = ((AP_FrameData*)m_pData)->m_pDocLayout->getHeight();
	int n, windowHeight;
	PtArg_t args[6];

	unsigned short tmp;
	UT_QNXGetWidgetArea(m_dArea, NULL, NULL, NULL, &tmp);
	windowHeight = tmp;

	int newvalue = ((m_pView) ? m_pView->getYScrollOffset() : 0);
	int newmax = height - windowHeight;	/* upper - page_size */
	if (newmax <= 0)
	{
		newmax=0;
		newvalue=0;
	}
	float slidersize;
	slidersize = (float)windowHeight / (float)newmax; 
	slidersize *= (float)windowHeight;

	n =0;
	PtSetArg(&args[n++], Pt_ARG_MAXIMUM, newmax, 0); 
	PtSetArg(&args[n++], Pt_ARG_INCREMENT, 20, 0); 
	PtSetArg(&args[n++], Pt_ARG_PAGE_INCREMENT, windowHeight, 0);
	PtSetArg(&args[n++], Pt_ARG_SCROLLBAR_POSITION, newvalue, 0);
	/* PtSetArg(&args[n++], Pt_ARG_SLIDER_SIZE, slidersize, 0);  */
	PtSetResources(m_vScroll, n, args);
	UT_DEBUGMSG(("Y SLIDER SIZE CHANGE TO %f (max %d) ", slidersize, newmax));

	/*
	bool bDifferentPosition = (newvalue != (int)m_pVadj->value);
	bool bDifferentLimits ((height-windowHeight) != (m_pVadj->upper-m_pVadj->page_size));
	*/
	bool bDifferentPosition = 1;
	bool bDifferentLimits = 1;

	//printf("Set Y limits to %d -[%d]- %d \n", 0, newvalue, newmax);

	if (m_pView && (bDifferentPosition || bDifferentLimits))
		m_pView->sendVerticalScrollEvent(newvalue, (long) height-windowHeight);
}


AP_QNXFrame::AP_QNXFrame(XAP_QNXApp * app)
	: XAP_QNXFrame(app)
{
	// TODO
	m_pData = NULL;
}

AP_QNXFrame::AP_QNXFrame(AP_QNXFrame * f)
	: XAP_QNXFrame((XAP_QNXFrame *)(f))
{
	// TODO
	m_pData = NULL;
}

AP_QNXFrame::~AP_QNXFrame(void)
{
	killFrameData();
}

bool AP_QNXFrame::initialize(void)
{
	if (!initFrameData())
		return false;

	if (!XAP_QNXFrame::initialize(AP_PREF_KEY_KeyBindings,AP_PREF_DEFAULT_KeyBindings,
								   AP_PREF_KEY_MenuLayout, AP_PREF_DEFAULT_MenuLayout,
								   AP_PREF_KEY_MenuLabelSet, AP_PREF_DEFAULT_MenuLabelSet,
								   AP_PREF_KEY_ToolbarLayouts, AP_PREF_DEFAULT_ToolbarLayouts,
								   AP_PREF_KEY_ToolbarLabelSet, AP_PREF_DEFAULT_ToolbarLabelSet))
		return false;

	_createTopLevelWindow();
	_showOrHideToolbars();
	_showOrHideStatusbar();
	_showOrHideRulers();
	PtRealizeWidget(m_wTopLevelWindow);
	PtDamageWidget(m_wTopLevelWindow);

	return true;
}

// Does the initial show/hide of toolbars (based on the user prefs).
// This is needed because toggleBar is called only when the user
// (un)checks the show {Stantandard,Format,Extra} toolbar checkbox,
// and thus we have to manually call this function at startup.
void AP_QNXFrame::_showOrHideToolbars(void)
{
    bool *bShowBar = static_cast<AP_FrameData*> (m_pData)->m_bShowBar;

    for (UT_uint32 i = 0; i < m_vecToolbarLayoutNames.getItemCount(); i++)
    {
        // TODO: The two next lines are here to bind the EV_Toolbar to the
        // AP_FrameData, but their correct place are next to the toolbar creation (JCA)
        EV_QNXToolbar * pQNXToolbar = static_cast<EV_QNXToolbar *> (m_vecToolbars.getNthItem(i));
        static_cast<AP_FrameData*> (m_pData)->m_pToolbar[i] = pQNXToolbar;
		//It is enabled by default .. only toggle it off
		if(!bShowBar[i]) {
	        toggleBar(i, bShowBar[i]);
		}
    }
}

// Does the initial show/hide of the rulers (based on user prefs)
void AP_QNXFrame::_showOrHideRulers(void)
{
	bool bShowRulers = static_cast<AP_FrameData*> (m_pData)->m_bShowRuler;
	//It is enabled by default .. only toggle it off
	if(!bShowRulers) {
		toggleRuler(bShowRulers);
	} 
}


// Does the initial show/hide of status bar (based on the user prefs).
void AP_QNXFrame::_showOrHideStatusbar(void)
{
    bool bShowStatusBar = static_cast<AP_FrameData*> (m_pData)->m_bShowStatusBar;
	//It is enabled by default .. only toggle it off
	if(!bShowStatusBar) {
    	toggleStatusBar(bShowStatusBar);
	} 
}

/*****************************************************************/

bool AP_QNXFrame::initFrameData(void)
{
	UT_ASSERT(!((AP_FrameData*)m_pData));

	AP_FrameData* pData = new AP_FrameData(m_pQNXApp);

	m_pData = (void*)pData;
	return (pData ? true : false);
}

void AP_QNXFrame::killFrameData(void)
{
	AP_FrameData* pData = (AP_FrameData*) m_pData;
	DELETEP(pData);
	m_pData = NULL;
}

UT_Error AP_QNXFrame::_loadDocument(const char * szFilename, IEFileType ieft, bool createNew)
{
	UT_DEBUGMSG(("Frame: _loadDocument %s (%d,%d)\n", (szFilename) ? szFilename : "", ieft, createNew));

	// are we replacing another document?
	if (m_pDoc)
	{
		// yep.  first make sure it's OK to discard it, 
		// TODO: query user if dirty...
	}

	// load a document into the current frame.
	// if no filename, create a new document.

	AD_Document * pNewDoc = new PD_Document(getApp());
	UT_ASSERT(pNewDoc);
	
	if (!szFilename || !*szFilename)
	{
		pNewDoc->newDocument();
		m_iUntitled = _getNextUntitledNumber();
		goto ReplaceDocument;
	}

	UT_Error errorCode; 
	errorCode = pNewDoc->readFromFile(szFilename, ieft);
	if (!errorCode)
		goto ReplaceDocument;

	// we have a file name but couldn't load it
	if (createNew) { 
	    pNewDoc->newDocument();
	    errorCode = pNewDoc->saveAs(szFilename, ieft);
	}
	if (!errorCode)
	  goto ReplaceDocument;
	
	UT_DEBUGMSG(("ap_Frame: could not open the file [%s]\n",szFilename));
	UNREFP(pNewDoc);
	return errorCode;

ReplaceDocument:
	getApp()->forgetClones(this);

	// NOTE: prior document is discarded in _showDocument()
	m_pDoc = pNewDoc;
	return UT_OK;
}

UT_Error AP_QNXFrame::_importDocument(const char * szFilename, int ieft,
									  bool markClean)
{
	// are we replacing another document?
	if (m_pDoc)
	{
		// yep.  first make sure it's OK to discard it, 
		// TODO: query user if dirty...
	}

	// load a document into the current frame.
	// if no filename, create a new document.

	AD_Document * pNewDoc = new PD_Document(getApp());
	UT_ASSERT(pNewDoc);
	
	if (!szFilename || !*szFilename)
	{
		pNewDoc->newDocument();
		m_iUntitled = _getNextUntitledNumber();
		goto ReplaceDocument;
	}
	UT_Error errorCode;
	errorCode = pNewDoc->importFile(szFilename, ieft, markClean);
	if (!errorCode)
		goto ReplaceDocument;

	UT_DEBUGMSG(("ap_Frame: could not open the file [%s]\n",szFilename));
	UNREFP(pNewDoc);
	return errorCode;

ReplaceDocument:
	getApp()->forgetClones(this);

	// NOTE: prior document is discarded in _showDocument()
	m_pDoc = pNewDoc;
	return UT_OK;
}

	
XAP_Frame * AP_QNXFrame::cloneFrame(void)
{
	AP_QNXFrame * pClone = new AP_QNXFrame(this);
	ENSUREP(pClone);
	return pClone;

Cleanup:
	// clean up anything we created here
	if (pClone)
	{
		m_pQNXApp->forgetFrame(pClone);
		delete pClone;
	}

	return NULL;
}

XAP_Frame * AP_QNXFrame::buildFrame(XAP_Frame * pF)
{
	UT_Error error = UT_OK;
	AP_QNXFrame * pClone = static_cast<	AP_QNXFrame *>(pF);
	ENSUREP(pClone);
	if (!pClone->initialize())
		goto Cleanup;

	error = pClone->_showDocument();
	if (error)
		goto Cleanup;

	pClone->show();

	return pClone;

Cleanup:
	// clean up anything we created here
	if (pClone)
	{
		m_pQNXApp->forgetFrame(pClone);
		delete pClone;
	}

	return NULL;
}

UT_Error AP_QNXFrame::loadDocument(const char * szFilename, int ieft, bool createNew)
{
	bool bUpdateClones;
	UT_Vector vClones;
	XAP_App * pApp = getApp();

	bUpdateClones = (getViewNumber() > 0);
	if (bUpdateClones)
	{
		pApp->getClones(&vClones, this);
	}
	UT_Error errorCode;
	errorCode =  _loadDocument(szFilename, (IEFileType) ieft, createNew);
	if (errorCode)
	{
		// we could not load the document.
		// we cannot complain to the user here, we don't know
		// if the app is fully up yet.  we force our caller
		// to deal with the problem.
		return errorCode;
	}

	pApp->rememberFrame(this);
	if (bUpdateClones)
	{
		for (UT_uint32 i = 0; i < vClones.getItemCount(); i++)
		{
			AP_QNXFrame * pFrame = (AP_QNXFrame *) vClones.getNthItem(i);
			if(pFrame != this)
			{
				pFrame->_replaceDocument(m_pDoc);
				pApp->rememberFrame(pFrame, this);
			}
		}
	}

	return _showDocument();
}

UT_Error AP_QNXFrame::loadDocument(const char * szFilename, int ieft)
{
	return loadDocument(szFilename, ieft, false);
}

UT_Error AP_QNXFrame::importDocument(const char * szFilename, int ieft,
									  bool markClean)
{
	bool bUpdateClones;
	UT_Vector vClones;
	XAP_App * pApp = getApp();

	bUpdateClones = (getViewNumber() > 0);
	if (bUpdateClones)
	{
		pApp->getClones(&vClones, this);
	}
	UT_Error errorCode;
	errorCode =  _importDocument(szFilename, (IEFileType) ieft, markClean);
	if (errorCode)
	{
		return errorCode;
	}

	pApp->rememberFrame(this);
	if (bUpdateClones)
	{
		for (UT_uint32 i = 0; i < vClones.getItemCount(); i++)
		{
			AP_QNXFrame * pFrame = (AP_QNXFrame *) vClones.getNthItem(i);
			if(pFrame != this)
			{
				pFrame->_replaceDocument(m_pDoc);
				pApp->rememberFrame(pFrame, this);
			}
		}
	}

	return _showDocument();
}

/*
 These functions are called whenever the position of the scrollbar
 might have changed.  Either from someone typeing in the window or
 because the window resized, or because the user grabbed the scrool
 bar and moved it.
*/
void AP_QNXFrame::_scrollFuncX(void * pData, UT_sint32 xoff, UT_sint32 /*xrange*/)
{
	PtArg_t args[1];
	//printf("Static X scroll function  \n");
	// this is a static callback function and doesn't have a 'this' pointer.
	
	AP_QNXFrame * pQNXFrame = (AP_QNXFrame *)(pData);
	AV_View * pView = pQNXFrame->getCurrentView();
	
	//Do some range checking ...

	PtSetArg(&args[0], Pt_ARG_SCROLLBAR_POSITION, xoff, 0);
	PtSetResources(pQNXFrame->m_hScroll, 1, args);

	pView->setXScrollOffset(xoff);
}

void AP_QNXFrame::_scrollFuncY(void * pData, UT_sint32 yoff, UT_sint32 /*yrange*/)
{
	PtArg_t args[1];
	//printf("Static Y scroll function  \n");

	// this is a static callback function and doesn't have a 'this' pointer.
	AP_QNXFrame * pQNXFrame = (AP_QNXFrame *)(pData);
	AV_View * pView = pQNXFrame->getCurrentView();
	
	//Do some range checking ...

	PtSetArg(&args[0], Pt_ARG_SCROLLBAR_POSITION, yoff, 0);
	PtSetResources(pQNXFrame->m_vScroll, 1, args);

	pView->setYScrollOffset(yoff);
}
	
PtWidget_t * AP_QNXFrame::_createDocumentWindow(void)
{
	PhArea_t area, savedarea;
	void * data = this;

	PtArg_t args[10];
	int n;

	/*TF DIFF: There is code here to not show
               the rulers, checked by
		bool bShowRulers = ((AP_FrameData*)m_pData)->m_bShowRuler;
	*/


#define SCROLLBAR_WIDTHHEIGHT 20
	// Strip the scrollbarwidth off the right and bottom
	// so that the scrollbars overlap the rulers
	savedarea = m_AvailableArea;
#if !defined(SCROLL_SMALLER_THAN_RULER) 
	m_AvailableArea.size.h -= SCROLLBAR_WIDTHHEIGHT; 
	m_AvailableArea.size.w -= SCROLLBAR_WIDTHHEIGHT; 
#endif

	// create the top ruler
	AP_QNXTopRuler * pQNXTopRuler = new AP_QNXTopRuler(this);
	UT_ASSERT(pQNXTopRuler);
	m_topRuler = pQNXTopRuler->createWidget();
	((AP_FrameData*)m_pData)->m_pTopRuler = pQNXTopRuler;

	// create the left ruler
	AP_QNXLeftRuler * pQNXLeftRuler = new AP_QNXLeftRuler(this);
	UT_ASSERT(pQNXLeftRuler);
	m_leftRuler = pQNXLeftRuler->createWidget();
	((AP_FrameData*)m_pData)->m_pLeftRuler = pQNXLeftRuler;

	// get the width from the left ruler and stuff it into the top ruler.
	pQNXTopRuler->setOffsetLeftRuler(pQNXLeftRuler->getWidth());

	// create the scrollbars horizontal then vertical

#if defined(SCROLL_SMALLER_THAN_RULER) 
	area.size.w = SCROLLBAR_WIDTHHEIGHT;
	area.size.h = m_AvailableArea.size.h - area.size.w;
	area.pos.y = m_AvailableArea.pos.y;
	area.pos.x = m_AvailableArea.pos.x + m_AvailableArea.size.w - area.size.w;
	m_AvailableArea.size.w -= area.size.w;
#else
	area.size.w = SCROLLBAR_WIDTHHEIGHT;
	area.size.h = savedarea.size.h - area.size.w;
	area.pos.y = savedarea.pos.y;
	area.pos.x = savedarea.pos.x + savedarea.size.w - area.size.w;
#endif

	n = 0;
	PtSetArg(&args[n++], Pt_ARG_AREA, &area, 0); 
#define _VS_ANCHOR_ (Pt_LEFT_ANCHORED_RIGHT | Pt_RIGHT_ANCHORED_RIGHT | \
		     Pt_TOP_ANCHORED_TOP | Pt_BOTTOM_ANCHORED_BOTTOM)
	PtSetArg(&args[n++], Pt_ARG_ANCHOR_FLAGS, _VS_ANCHOR_, _VS_ANCHOR_); 
	PtSetArg(&args[n++], Pt_ARG_SCROLLBAR_FLAGS, Pt_SCROLLBAR_FOCUSED | 0 /*Vertical*/, 
									 		     Pt_SCROLLBAR_FOCUSED | 0 /*Vertical*/); 
	PtSetArg(&args[n++], Pt_ARG_FLAGS, 0, Pt_GETS_FOCUS);
	PtSetArg(&args[n++], Pt_ARG_ORIENTATION, 0 /*Vertical*/, 0); 
	m_vScroll = PtCreateWidget(PtScrollbar, getTopLevelWindow(), n, args);
	PtAddCallback(m_vScroll, Pt_CB_SCROLL_MOVE, _fe::vScrollChanged, this);

#if defined(SCROLL_SMALLER_THAN_RULER) 
	area.size.h = SCROLLBAR_WIDTHHEIGHT;
	area.size.w = m_AvailableArea.size.w;
	area.pos.y = m_AvailableArea.pos.y + m_AvailableArea.size.h - area.size.h;
	area.pos.x = m_AvailableArea.pos.x;
	m_AvailableArea.size.h -= area.size.h;
#else
	area.size.h = SCROLLBAR_WIDTHHEIGHT;
	area.size.w = savedarea.size.w - SCROLLBAR_WIDTHHEIGHT;
	area.pos.y = savedarea.pos.y + savedarea.size.h - area.size.h;
	area.pos.x = savedarea.pos.x;
#endif

	n = 0;
	PtSetArg(&args[n++], Pt_ARG_AREA, &area, 0); 
#define _HS_ANCHOR_ (Pt_LEFT_ANCHORED_LEFT | Pt_RIGHT_ANCHORED_RIGHT | \
		     Pt_TOP_ANCHORED_BOTTOM | Pt_BOTTOM_ANCHORED_BOTTOM)
	PtSetArg(&args[n++], Pt_ARG_ANCHOR_FLAGS, _HS_ANCHOR_, _HS_ANCHOR_); 
	PtSetArg(&args[n++], Pt_ARG_SCROLLBAR_FLAGS, Pt_SCROLLBAR_FOCUSED | 1 /*Horizontal*/,
									 			 Pt_SCROLLBAR_FOCUSED | 1 /*Horizontal*/); 
	PtSetArg(&args[n++], Pt_ARG_FLAGS, 0, Pt_GETS_FOCUS); 
	PtSetArg(&args[n++], Pt_ARG_ORIENTATION, 1 /*Horizontal*/, 0); 
	m_hScroll = PtCreateWidget(PtScrollbar, getTopLevelWindow(), n, args);
	PtAddCallback(m_hScroll, Pt_CB_SCROLL_MOVE, _fe::hScrollChanged, this);

	// create a drawing area in the for our document window.

	area.pos.x = m_AvailableArea.pos.x;
	area.pos.y = m_AvailableArea.pos.y;
	area.size.w = m_AvailableArea.size.w; 
	area.size.h = m_AvailableArea.size.h;

	n = 0;
	PtSetArg(&args[n++], Pt_ARG_AREA, &area, 0); 
	PtSetArg(&args[n++], Pt_ARG_GROUP_ORIENTATION, Pt_GROUP_VERTICAL, Pt_GROUP_VERTICAL);
#define _DA_ANCHOR_ (Pt_LEFT_ANCHORED_LEFT | Pt_RIGHT_ANCHORED_RIGHT | \
		     Pt_TOP_ANCHORED_TOP | Pt_BOTTOM_ANCHORED_BOTTOM)
	PtSetArg(&args[n++], Pt_ARG_ANCHOR_FLAGS, _DA_ANCHOR_, _DA_ANCHOR_);
#define _DA_STRETCH_ (Pt_GROUP_STRETCH_VERTICAL | Pt_GROUP_STRETCH_HORIZONTAL)
	PtSetArg(&args[n++], Pt_ARG_GROUP_FLAGS, _DA_STRETCH_, _DA_STRETCH_);
	PtSetArg(&args[n++], Pt_ARG_USER_DATA, &data, sizeof(this)); 
	m_dAreaGroup = PtCreateWidget(PtGroup, getTopLevelWindow(), n, args);
	PtAddCallback(m_dAreaGroup, Pt_CB_RESIZE, &(_fe::resize), this);
	
	n = 0;
	PtSetArg(&args[n++], Pt_ARG_DIM, &area.size, 0); 
	PtSetArg(&args[n++], Pt_ARG_USER_DATA, &data, sizeof(this)); 
	PtSetArg(&args[n++], Pt_ARG_RAW_DRAW_F, &(_fe::expose), 1); 
	PtSetArg(&args[n++], Pt_ARG_FLAGS, Pt_GETS_FOCUS, Pt_GETS_FOCUS); 
	m_dArea = PtCreateWidget(PtRaw, m_dAreaGroup, n, args); 

	PtAddEventHandler(m_dArea, Ph_EV_KEY, _fe::key_press_event, this);
	PtAddEventHandler(m_dArea, Ph_EV_PTR_MOTION_BUTTON, _fe::motion_notify_event, this);
	PtAddEventHandler(m_dArea, Ph_EV_BUT_PRESS, _fe::button_press_event, this);
	PtAddEventHandler(m_dArea, Ph_EV_BUT_RELEASE, _fe::button_release_event, this);

	return(m_dAreaGroup);
}

//This might be the place to do our co-ordinate conversions ...
void AP_QNXFrame::translateDocumentToScreen(UT_sint32 &x, UT_sint32 &y)
{
	printf("TODO: Translate Document To Screen %d,%d \n", x, y);
}

PtWidget_t * AP_QNXFrame::_createStatusBarWindow(void)
{
	AP_QNXStatusBar * pQNXStatusBar = new AP_QNXStatusBar(this);
	UT_ASSERT(pQNXStatusBar);

	((AP_FrameData *)m_pData)->m_pStatusBar = pQNXStatusBar;
	
	//This should probably be held in XP land
	m_wStatusBar = pQNXStatusBar->createWidget();

	return m_wStatusBar;
}

void AP_QNXFrame::setStatusMessage(const char * szMsg)
{
PhDrawContext_t *context=PhDCGetCurrent();
//XXX: A bit of a hack, checking if the current context is a print context, if so, ignore.
//This is because this function is called to update the toolbar while printing.
	if(context->type & 0x1) 
		return; 
	if(PtWidgetIsRealized(m_wStatusBar) != 0) {
		((AP_FrameData *)m_pData)->m_pStatusBar->setStatusMessage(szMsg);
	}
}

void AP_QNXFrame::_setWindowIcon(void)
{
	//Photon relies on the icon being bound into the executable resource
}

UT_Error AP_QNXFrame::_replaceDocument(AD_Document * pDoc)
{
	// NOTE: prior document is discarded in _showDocument()
	m_pDoc = REFP(pDoc);

	return _showDocument();
}

void AP_QNXFrame::toggleBar(UT_uint32 iBarNb, bool bBarOn) {
	int		before, after;
	unsigned short *height;

    AP_FrameData *pFrameData = static_cast<AP_FrameData *> (getFrameData());
    UT_ASSERT(pFrameData);

	PtGetResource(getTBGroupWidget(), Pt_ARG_HEIGHT, &height, 0);
	before = *height;

    if (bBarOn) {
        pFrameData->m_pToolbar[iBarNb]->show();
    }
    else {
        pFrameData->m_pToolbar[iBarNb]->hide();
    }

	PtExtentWidgetFamily(getTBGroupWidget());
	PtGetResource(getTBGroupWidget(), Pt_ARG_HEIGHT, &height, 0);
	after = *height;

	_reflowLayout(0, before - after, 0, 0);
}

void AP_QNXFrame::toggleTopRuler(bool bRulerOn)
{
	unsigned short *height;

	PtGetResource(m_topRuler, Pt_ARG_HEIGHT, &height, 0);

	if (bRulerOn) {
		PtRealizeWidget(m_topRuler);
		_reflowLayout(0, 0, -(*height), 0);
	} else {
		PtUnrealizeWidget(m_topRuler);
		PtSetResource(m_topRuler, Pt_ARG_FLAGS, Pt_DELAY_REALIZE, Pt_DELAY_REALIZE);
		_reflowLayout(0, 0, *height, 0);
	}
}

void AP_QNXFrame::toggleLeftRuler(bool bRulerOn)
{
	unsigned short *width;

	PtGetResource(m_leftRuler, Pt_ARG_WIDTH, &width, 0);

	if (bRulerOn) {
		PtRealizeWidget(m_leftRuler);
//		_reflowLayout(0, 0, 0, - (*width));
	} else {
		PtRealizeWidget(m_leftRuler);		
		PtSetResource(m_leftRuler, Pt_ARG_FLAGS, Pt_DELAY_REALIZE, Pt_DELAY_REALIZE);
		_reflowLayout(0, 0, 0, (*width));
	}
}

void AP_QNXFrame::toggleRuler(bool bRulerOn)
{
	AP_FrameData *pFrameData = (AP_FrameData *)getFrameData();
	UT_ASSERT(pFrameData);

	toggleTopRuler(bRulerOn);
	toggleLeftRuler(bRulerOn && (pFrameData->m_pViewMode == VIEW_PRINT));
}


void AP_QNXFrame::toggleStatusBar(bool bStatusBarOn) {
	int height;
    AP_FrameData *pFrameData = static_cast<AP_FrameData *> (getFrameData());
    UT_ASSERT(pFrameData);

	height = pFrameData->m_pStatusBar->getHeight();
    if (bStatusBarOn) {
		_reflowLayout(-height, 0, 0, 0);
        pFrameData->m_pStatusBar->show();
    }
    else {
        pFrameData->m_pStatusBar->hide();
		_reflowLayout(height, 0, 0, 0);
    }

}

void AP_QNXFrame::setDocumentFocus() {
	PtContainerGiveFocus(m_dArea, NULL);
}
void XAP_QNXFrame::setCursor(GR_Graphics::Cursor c)
{
//XXX: gotta add content.
}



/*** THIS CODE WILL GO AWAY WITH AN INTELLIGENT LAYOUT THINGY ***/
void AP_QNXFrame::_reflowLayout(int loweradj, int upperadj, int topruleradj, int leftruleradj) {
	PhArea_t 	newarea, *oldarea;
	/*
     loweradj < 0 means we are enabling and > 0 means disabling
	*/
	if(loweradj != 0) { 	
		PtGetResource(m_hScroll, Pt_ARG_AREA, &oldarea, 0);
		newarea = *oldarea;
		newarea.pos.y += loweradj;
		PtSetResource(m_hScroll, Pt_ARG_AREA, &newarea, 0);

		PtGetResource(m_vScroll, Pt_ARG_AREA, &oldarea, 0);
		newarea = *oldarea;
		newarea.size.h += loweradj;
		PtSetResource(m_vScroll, Pt_ARG_AREA, &newarea, 0);

		PtGetResource(m_leftRuler, Pt_ARG_AREA, &oldarea, 0);
		newarea = *oldarea;
		newarea.size.h += loweradj;
		PtSetResource(m_leftRuler, Pt_ARG_AREA, &newarea, 0);

		PtGetResource(m_dAreaGroup, Pt_ARG_AREA, &oldarea, 0);
		newarea = *oldarea;
		newarea.size.h += loweradj;
		PtSetResource(m_dAreaGroup, Pt_ARG_AREA, &newarea, 0);
	} 

	/*
	 upperadj < 0 means we are enabling an > 0 means disabling
	*/
	if(upperadj != 0) {
		PtGetResource(m_vScroll, Pt_ARG_AREA, &oldarea, 0);
		newarea = *oldarea;
		newarea.pos.y -= upperadj;
		newarea.size.h += upperadj;
		PtSetResource(m_vScroll, Pt_ARG_AREA, &newarea, 0);

		PtGetResource(m_topRuler, Pt_ARG_AREA, &oldarea, 0);
		newarea = *oldarea;
		newarea.pos.y -= upperadj;
		PtSetResource(m_topRuler, Pt_ARG_AREA, &newarea, 0);
	}

	if(topruleradj != 0 || upperadj != 0) {
		PtGetResource(m_leftRuler, Pt_ARG_AREA, &oldarea, 0);
		newarea = *oldarea;
		newarea.pos.y -= upperadj;
		newarea.size.h += upperadj;
		PtSetResource(m_leftRuler, Pt_ARG_AREA, &newarea, 0);

		PtGetResource(m_dAreaGroup, Pt_ARG_AREA, &oldarea, 0);
		newarea = *oldarea;
		newarea.pos.y -= upperadj + topruleradj;
		newarea.size.h += upperadj + topruleradj;
		PtSetResource(m_dAreaGroup, Pt_ARG_AREA, &newarea, 0);
	}

	if(leftruleradj != 0) {
		PtGetResource(m_dAreaGroup, Pt_ARG_AREA, &oldarea, 0);
		newarea = *oldarea;
		newarea.pos.x -= leftruleradj;
		newarea.size.w += leftruleradj;
		PtSetResource(m_dAreaGroup, Pt_ARG_AREA, &newarea, 0);
	}
}
