bool XAP_App::updateClones(XAP_Frame * pFrame)
{
	UT_return_val_if_fail(pFrame,false);
	UT_ASSERT(pFrame->getViewNumber() > 0);

	// locate vector of this frame's clones
	UT_GenericVector<XAP_Frame*>* pEntry = m_hashClones.pick(pFrame->getViewKey());
	UT_ASSERT_HARMLESS(pEntry);

	if (pEntry)
	{
		UT_GenericVector<XAP_Frame*>* pvClones = pEntry;
		UT_return_val_if_fail(pvClones,false);

		UT_uint32 count = pvClones->getItemCount();
		UT_ASSERT(count > 0);
		XAP_Frame * f = NULL;

		for (UT_uint32 j=0; j<count; j++)
		{
			f = pvClones->getNthItem(j);
			UT_continue_if_fail(f);

			f->updateTitle();
		}
	}

	return true;
}
bool XAP_App::rememberFrame(XAP_Frame * pFrame, XAP_Frame * pCloneOf)
{
	UT_ASSERT(pFrame);

	// add this frame to our window list
	m_vecFrames.addItem(pFrame);

	if(! m_lastFocussedFrame)
	    rememberFocussedFrame(pFrame);

	// TODO: error-check the following for mem failures
	if (pCloneOf)
	{
		// locate vector of this frame's clones
		UT_GenericVector<XAP_Frame*> * pEntry = m_hashClones.pick(pCloneOf->getViewKey());
		UT_GenericVector<XAP_Frame*> * pvClones = NULL;

		if (pEntry)
		{
			// hash table entry already exists
			pvClones = pEntry;

			if (!pvClones)
			{
				// nothing there, so create a new one
				pvClones = new UT_GenericVector<XAP_Frame*>();
				UT_return_val_if_fail(pvClones,false);

				pvClones->addItem(pCloneOf);

				// reuse this slot
				m_hashClones.set(pCloneOf->getViewKey(), pvClones);
			}
		}
		else
		{
			// create a new one
			pvClones = new UT_GenericVector<XAP_Frame*>();
			UT_return_val_if_fail(pvClones,false);

			pvClones->addItem(pCloneOf);

			// add it to the hash table
			m_hashClones.insert(pCloneOf->getViewKey(), pvClones);
		}

		pvClones->addItem(pFrame);

		// notify all clones of their new view numbers
		for (UT_sint32 j=0; j<pvClones->getItemCount(); j++)
		{
			XAP_Frame * f = pvClones->getNthItem(j);
			UT_continue_if_fail(f);

			f->setViewNumber(j+1);

			if (f != pFrame)
				f->updateTitle();
		}
	}
	
	// TODO do something here...
	notifyFrameCountChange();
	return true;
}
bool XAP_App::forgetFrame(XAP_Frame * pFrame)
{
	UT_return_val_if_fail(pFrame,false);

	// If this frame is the currently focussed frame write in NULL
	// until another frame appears

	if(pFrame == m_lastFocussedFrame )
	{
		m_lastFocussedFrame = static_cast<XAP_Frame *>(NULL);
	}

	if (pFrame->getViewNumber() > 0)
	{
		// locate vector of this frame's clones
		UT_GenericVector<XAP_Frame*>* pEntry = m_hashClones.pick(pFrame->getViewKey());
		UT_ASSERT(pEntry);

		if (pEntry)
		{
			UT_GenericVector<XAP_Frame*> * pvClones = pEntry;
			UT_return_val_if_fail(pvClones,false);

			// remove this frame from the vector
			UT_sint32 i = pvClones->findItem(pFrame);
			UT_ASSERT(i >= 0);

			if (i >= 0)
			{
				pvClones->deleteNthItem(i);
			}

			// see how many clones are left
			UT_uint32 count = pvClones->getItemCount();
			UT_ASSERT(count > 0);
			XAP_Frame * f = NULL;

			if (count == 1)
			{
				// remaining clone is now a singleton
				f = pvClones->getNthItem(count-1);
				UT_return_val_if_fail(f,false);

				f->setViewNumber(0);
				f->updateTitle();

				// remove this entry from hashtable
				m_hashClones.remove(f->getViewKey(), 
						    NULL);
				delete pvClones;
			}
			else
			{
				// notify remaining clones of their new view numbers
				for (UT_uint32 j=0; j<count; j++)
				{
					f = static_cast<XAP_Frame *>(pvClones->getNthItem(j));
					UT_continue_if_fail(f);

					f->setViewNumber(j+1);
					f->updateTitle();
				}
			}
		}
	}

	// remove this frame from our window list
	UT_sint32 ndx = m_vecFrames.findItem(pFrame);
	UT_ASSERT_HARMLESS(ndx >= 0);

	if (ndx >= 0)
	{
		m_vecFrames.deleteNthItem(ndx);
		notifyFrameCountChange();
	}

	notifyModelessDlgsCloseFrame(pFrame);

	// TODO do something here...

	return true;
}
bool XAP_App::retrieveState()
{
	XAP_StateData sd;

	bool bRet = true;
	
	if(!_retrieveState(sd))
		return false;

	UT_return_val_if_fail(sd.iFileCount <= XAP_SD_MAX_FILES, false);
		
	// now do our thing with it:
	//  * open the files stored in the data
	//  * move carets and scrollbars to the saved positions
	//  * make the first saved frame to be the current frame

	// we should only be restoring state with no docs already
	// opened
	UT_return_val_if_fail(m_vecFrames.getItemCount() <= 1, false);
	XAP_Frame * pFrame = NULL;

	if(m_vecFrames.getItemCount())
		pFrame = m_vecFrames.getNthItem(0);

	// if there is a frame, it should be one with unmodified untitled document
	UT_return_val_if_fail( !pFrame || (!pFrame->getFilename() && !pFrame->isDirty()), false );
		
	UT_Error errorCode = UT_IE_IMPORTERROR;
	
	for(UT_uint32 i = 0; i < sd.iFileCount; ++i)
	{
		if(!pFrame)
			pFrame = newFrame();
		
		if (!pFrame)
			return false;
		
		// Open a complete but blank frame, then load the document into it
		errorCode = pFrame->loadDocument((const char *)NULL, 0 /*IEFT_Unknown*/);

		bRet &= (errorCode == UT_OK);
		
		if (errorCode == UT_OK)
			pFrame->show();
	    else
			continue;

		errorCode = pFrame->loadDocument(sd.filenames[i], 0 /*IEFT_Unknown*/);

		bRet &= (errorCode == UT_OK);
		
		if (errorCode != UT_OK)
			continue;

		pFrame->show();

		AV_View* pView = pFrame->getCurrentView();
		if(!pView)
		{
			UT_ASSERT_HARMLESS( UT_SHOULD_NOT_HAPPEN );
			bRet = false;
			continue;
		}
		
		pView->setPoint(sd.iDocPos[i]);
		pView->setXScrollOffset(sd.iXScroll[i]);
		pView->setYScrollOffset(sd.iYScroll[i]);

		// now we check if this doc was autosaved Untitled* doc at hibernation
		char * p = strstr(sd.filenames[i], HIBERNATED_EXT);
		if(p)
		{
			// remove extension
			p = 0;
			AD_Document * pDoc = pFrame->getCurrentDoc();

			if(pDoc)
			{
				pDoc->clearFilename();
				pDoc->forceDirty();
				pFrame->updateTitle();
			}
		}
		
		
		// frame used -- next doc needs a new one
		pFrame = NULL;
	}

	// set focus to the first frame
	pFrame = m_vecFrames.getNthItem(0);
	UT_return_val_if_fail( pFrame, false );

	AV_View* pView = pFrame->getCurrentView();
	UT_return_val_if_fail( pView, false );

	pView->focusChange(AV_FOCUS_HERE);

	return bRet;
}