symhelp/helpmodel/tsrc/THelpView.cpp
changeset 0 1f04cf54edd8
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/symhelp/helpmodel/tsrc/THelpView.cpp	Tue Jan 26 15:15:23 2010 +0200
@@ -0,0 +1,692 @@
+// Copyright (c) 1999-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+//
+
+#pragma message(__FILE__ "(5) : This test code memory leaks on exit due to a bug in the code...fix when have time")
+
+#include "THelpView.h"
+
+// System includes
+#include <coemain.h>
+#include <eikenv.h>
+#include <techview/eikrted.h>
+#include <techview/eikmenup.h>
+#include <techview/eikchlst.h>
+#include <techview/eikon.hrh>
+#include <techview/eiksbfrm.h>
+#include <eikstart.h>
+#include <txtrich.h>
+#include "hlpmodel.h"
+#include <thelpview.rsg>
+
+// User includes
+#include "thelpviewctrls.h"
+#include "THelpView.hrh"
+
+// Constants
+const TInt KSizeSearchPromptIndent = 5;
+const TInt KSizeSearchPromptHeight = 25;
+const TInt KResultsViewWidth = 150;
+
+// Panic enum
+enum THlpViewerPanic
+	{
+	EHlpViewPanicNoSearchSpec
+	};
+
+
+//
+// ----> Global functions / Entry points (source)
+//
+
+LOCAL_C CApaApplication* NewApplication()
+// Ordinal 1 export for App Dll's
+	{
+	return new CHlpApplication();
+	}
+
+GLDEF_C TInt E32Main()
+	{
+	return EikStart::RunApplication(NewApplication);
+	}
+
+
+void Panic(THlpViewerPanic aPanic)
+	{
+	_LIT(KHlpViewPanicCategory, "HlpView");
+	User::Panic(KHlpViewPanicCategory, aPanic);
+	}
+
+
+
+//
+// ----> CHlpApplication (source)
+//
+TUid CHlpApplication::AppDllUid() const
+	{
+	return KUidHelpViewApp;
+	}
+
+CApaDocument* CHlpApplication::CreateDocumentL()
+	{
+	CHlpDocument* document = new(ELeave) CHlpDocument(*this);
+	CleanupStack::PushL(document);
+	document->NewDocumentL();
+	CleanupStack::Pop();
+	return document;
+	}
+
+
+
+
+
+//
+// ----> CHlpAppUi (source)
+//
+CHlpDocument::CHlpDocument(CEikApplication& aApp)
+:	CEikDocument(aApp)
+	{
+	}
+
+CHlpDocument::~CHlpDocument()
+	{
+	delete iModel;
+	}
+
+CEikAppUi* CHlpDocument::CreateAppUiL()
+	{
+    return(new(ELeave) CHlpAppUi());
+	}
+
+void CHlpDocument::NewDocumentL()
+	{
+	CHlpModel* model = CHlpModel::NewL(Process()->FsSession(), NULL);
+	CleanupStack::PushL(model);
+	model->OpenL();
+	delete iModel;
+	iModel = model;
+	CleanupStack::Pop(); // model
+	}
+
+
+
+
+
+//
+// ----> CHlpAppUi (source)
+//
+CHlpAppUi::~CHlpAppUi()
+	{
+	CCoeAppUi::RemoveFromStack(iView);
+	delete iView;
+	}
+
+void CHlpAppUi::ConstructL()
+	{
+    BaseConstructL();
+
+	iView = new(ELeave) CHlpMainView(*this, Document().Model());
+	iView->ConstructL();
+	iView->SetRect(ClientRect());
+
+	AddToStackL(iView);
+	}
+
+//
+// FROM CEikAppUi
+//
+
+void CHlpAppUi::HandleCommandL(TInt aCommand)
+	{
+	switch (aCommand)
+		{
+	case EEikCmdExit: 
+		Exit();
+		break;
+
+	case EHlpCmdSearch:
+		iView->ShowSearchPrompt(ETrue);
+		break;
+
+	case EHlpCmdSearchDone:
+		iView->MakeResultsVisible(EFalse);
+		break;
+
+	case EEikCmdZoomIn:
+	case EEikCmdZoomOut:
+		HandleZoomL(aCommand);	
+		break;
+
+	default:
+		User::Leave(KErrNotSupported);
+		break;
+		}
+	}
+
+void CHlpAppUi::DynInitMenuPaneL(TInt aMenuId, CEikMenuPane* aMenuPane)
+	{
+	switch (aMenuId)
+		{
+	case R_HELPVIEW_TOOLS_MENU:
+		aMenuPane->SetItemDimmed(EHlpCmdSearchDone, !iView->IsSearchResultVisible());
+		break;
+		}
+	}
+
+//
+// NEW
+//
+
+void CHlpAppUi::HandleZoomL(TInt aZoomEvent)
+	{
+	if	(!iZoomHandler)
+		return;
+	iZoomHandler->HandleZoomEventL(STATIC_CAST(MZoomableControl::TZoomEvent, aZoomEvent));
+	}
+
+
+
+
+
+
+//
+// ----> CHlpView (source)
+//
+CHlpView::CHlpView(CHlpAppUi& aAppUi, CHlpModel& aModel)
+:	iAppUi(aAppUi), iHelpModel(aModel), iCurrentZoom(EZoomStateTwo)
+	{
+	}
+
+CHlpView::~CHlpView()
+	{
+	delete iHelpCategories;
+	delete iHelpTopicsForCategory;
+	delete iRichTextEditor;
+	delete iCurrentTopics;
+	delete iLastTopic;
+
+	// Remove this when the memory leak is finished...
+	iCoeEnv->DisableExitChecks(ETrue);
+	}
+
+void CHlpView::ConstructL()
+	{
+	iLastTopic = CHlpTopic::NewL();
+	iZoom.SetGraphicsDeviceMap(iCoeEnv->ScreenDevice());
+
+	iHelpModel.SetObserver(this);
+
+	iHelpCategories = new(ELeave) CEikChoiceList();
+	iHelpCategories->SetContainerWindowL(*this);
+	iHelpCategories->SetFocus(ETrue);
+	iHelpCategories->SetObserver(this);
+
+	iHelpTopicsForCategory = new(ELeave) CEikChoiceList();
+	iHelpTopicsForCategory->SetContainerWindowL(*this);
+	iHelpTopicsForCategory->SetObserver(this);
+
+	iRichTextEditor = new(ELeave) CEikRichTextEditor();
+	iRichTextEditor->SetContainerWindowL(*this);
+	iRichTextEditor->ConstructL(this, 6, 100000, CEikEdwin::EWidthInPixels | CEikEdwin::EReadOnly | CEikEdwin::ENoAutoSelection | CEikEdwin::EKeepDocument);
+	iRichTextEditor->SetZoomFactorL(&iZoom);
+	iRichTextEditor->CreateTextViewL();
+	iRichTextEditor->CreateScrollBarFrameL()->SetScrollBarVisibilityL(CEikScrollBarFrame::EOff, CEikScrollBarFrame::EAuto);
+	iRichTextEditor->SetObserver(this);
+
+	HandleZoomEventL(EEventZoomDefault);
+	PopulateCategoryListL();
+
+	iHelpModel.SetZoomFactors(EHlpZoomStateSmall, 750);
+	iHelpModel.SetZoomFactors(EHlpZoomStateMedium, 1000);
+	iHelpModel.SetZoomFactors(EHlpZoomStateLarge, 1250);
+	}
+
+
+//
+// NEW
+//
+void CHlpView::PopulateCategoryListL()
+	{
+	// First get a category listing, then get the list of topics
+	// for each specified category.
+	// Get and print the category listing
+	CDesCArrayFlat* array = new(ELeave) CDesCArrayFlat(5);
+	CleanupStack::PushL(array);
+	iHelpModel.CategoryListL(array);
+
+	if	(!array->Count())
+		User::Leave(KErrArgument); // ??
+
+	iHelpCategories->SetArrayExternalOwnership(EFalse);
+	iHelpCategories->SetArrayL(array);
+	iHelpCategories->SetArrayExternalOwnership(EFalse);
+	iHelpCategories->SetCurrentItem(0);
+
+	PopulateTopicListL(iHelpCategories->Array()->MdcaPoint(iHelpCategories->CurrentItem()));
+
+	CleanupStack::Pop();
+	}
+
+void CHlpView::PopulateTopicListL(const TDesC& aTopic)
+	{
+	iHelpModel.SearchL(ETopicListForCategory, aTopic);
+
+	CHlpList* list = CHlpList::NewLC();
+	iHelpModel.LoadListL(list);
+	iHelpTopicsForCategory->SetArrayL(list); // Derrives from MDesCArray so we can do this
+	delete iCurrentTopics;
+	iCurrentTopics = list;
+	iHelpTopicsForCategory->SetArrayExternalOwnership(ETrue); // owned by this class
+	CleanupStack::Pop(); // list
+
+	if	(list->MdcaCount())
+		{
+		UpdateEdwinL(*list->Item(0));
+		iHelpTopicsForCategory->SetCurrentItem(0);
+		iHelpTopicsForCategory->DrawNow();
+		}
+	}
+
+
+void CHlpView::UpdateEdwinL(const CHlpItem& aItem)
+//
+//	Extract the rich text from the help file and display it in the
+//	read only edit window.
+//
+	{
+	// Search for a specific topic.
+	iHelpModel.TopicSearchL(aItem);
+	if	(iLastResponseFromHelpModel == ETopicAvailable)
+		{
+		CHlpTopic* topic = CHlpTopic::NewLC();
+		iHelpModel.LoadTopicL(topic);
+		iRichTextEditor->SetDocumentContentL(*topic->TopicText(), CEikEdwin::EUseText);
+		iRichTextEditor->NotifyNewFormatL();
+		iRichTextEditor->TextView()->SetViewLineAtTopL(1);
+		iRichTextEditor->UpdateScrollBarsL();
+		delete iLastTopic;
+		iLastTopic = topic;
+		CleanupStack::Pop(); // topic
+		}
+	else
+		iEikonEnv->InfoMsg(R_HELPVIEW_TEXT_NO_TOPIC_FOR_ID);
+	}
+
+//
+// FROM MZoomableControl
+//
+
+void CHlpView::HandleZoomEventL(TZoomEvent aEvent)
+	{
+	switch(aEvent)
+		{
+	case EEventZoomIn:
+		if	(++iCurrentZoom>=KNumberOfZoomStates)
+			iCurrentZoom = 0;
+		break;
+	case EEventZoomOut:
+		if	(--iCurrentZoom < 0)
+			iCurrentZoom = KNumberOfZoomStates-1;
+		break;
+	case EEventZoomDefault:
+		iCurrentZoom = 1;
+		break;
+	default:
+		User::Leave(KErrNotSupported);
+		}
+
+	// Select bitmap zoom size in the 'hlpmodel', according to the value of 'iCurrentZoom'
+	switch (iCurrentZoom)
+		{
+	case 0:
+		iHelpModel.SetZoomSizeL(EHlpZoomStateSmall);
+		break;
+	default:
+	case 1:
+		iHelpModel.SetZoomSizeL(EHlpZoomStateMedium);
+		break;
+	case 2:
+		iHelpModel.SetZoomSizeL(EHlpZoomStateLarge);
+		break;
+		}
+
+
+	iZoom.SetZoomFactor(ZoomForIndex(iCurrentZoom));
+	iRichTextEditor->NotifyNewFormatL();
+	iRichTextEditor->UpdateScrollBarsL();
+	iRichTextEditor->DrawNow();
+	}
+
+TInt CHlpView::ZoomForIndex(TInt aIndex)
+	{
+	switch(aIndex)
+		{
+	case 0:
+		return EZoomStateOne;
+	default:
+	case 1:
+		return EZoomStateTwo;
+	case 2:
+		return EZoomStateThree;
+		}
+	}
+
+//
+// FROM CCoeControl
+//
+
+void CHlpView::SizeChanged()
+	{
+	const TInt KKludgeFactor = 4;
+
+	TRect rect(Position(), Rect().Size());
+	TSize choiceListSize = iHelpCategories->MinimumSize() + TSize(0, KKludgeFactor);
+
+	TPoint topLeft(rect.iTl);
+
+	iHelpCategories->SetExtent(topLeft, TSize(rect.Width()/2, choiceListSize.iHeight));
+	iHelpTopicsForCategory->SetExtent(TPoint(rect.Size().iWidth/2,topLeft.iY), TSize(rect.Size().iWidth/2, choiceListSize.iHeight));
+	iRichTextEditor->SetRect(TRect(TPoint(topLeft.iX, choiceListSize.iHeight), rect.iBr));
+	}
+
+TInt CHlpView::CountComponentControls() const
+	{
+	return 3;
+	}
+
+CCoeControl* CHlpView::ComponentControl(TInt aIndex) const
+	{
+	switch (aIndex)
+		{
+	default:
+	case 0:
+		return iHelpCategories;
+	case 1:
+		return iHelpTopicsForCategory;
+	case 2:
+		return iRichTextEditor;
+		}
+	}
+
+TKeyResponse CHlpView::OfferKeyEventL(const TKeyEvent& aKeyEvent,TEventCode aType)
+	{
+	return iRichTextEditor->OfferKeyEventL(aKeyEvent, aType);
+	}
+
+//
+// FROM MCoeControlObserver
+//
+void CHlpView::HandleControlEventL(CCoeControl* aControl, TCoeEvent aEventType)
+	{
+	if	(aEventType == EEventRequestFocus)
+		{
+		if	(iFocusedControl)
+			{
+			iFocusedControl->PrepareForFocusLossL();
+			iFocusedControl->SetFocus(EFalse);
+			}
+		iFocusedControl = aControl;
+		iFocusedControl->SetFocus(ETrue);
+		}
+	else if	(aControl == iHelpCategories && aEventType == EEventStateChanged)
+		{
+		// Update the list of topics available for this category
+		PopulateTopicListL(iHelpCategories->Array()->MdcaPoint(iHelpCategories->CurrentItem()));
+		}
+	else if	(aControl == iHelpTopicsForCategory && aEventType == EEventStateChanged)
+		{
+		// Update the edwin contents
+		UpdateEdwinL(*iCurrentTopics->Item(iHelpTopicsForCategory->CurrentItem()));
+		}
+	}
+
+//
+// FROM MHlpModelObserver
+//
+void CHlpView::HandleModelEventL(TInt aEvent)
+	{
+	iLastResponseFromHelpModel = aEvent;
+	}
+
+
+
+
+
+
+
+//
+// ----> CHlpMainView (source)
+//
+
+CHlpMainView::CHlpMainView(CHlpAppUi& aAppUi, CHlpModel& aModel)
+:	iAppUi(aAppUi), iModel(aModel)
+	{
+	}
+
+CHlpMainView::~CHlpMainView()
+	{
+	delete iSearchResults;
+	delete iSearchPrompt;
+	delete iView;
+	}
+
+void CHlpMainView::ConstructL()
+	{
+	CreateWindowL();
+
+	iView = new(ELeave) CHlpView(iAppUi, iModel);
+	iView->SetContainerWindowL(*this);
+	iView->ConstructL();
+	iAppUi.SetZoomHandler(iView);
+
+	iSearchPrompt = new(ELeave) CHlpSearchPrompt();
+	iSearchPrompt->ConstructL(*this);
+	iSearchPrompt->SetObserver(this);
+	iSearchPrompt->MakeVisible(EFalse);
+
+	iSearchResults = new(ELeave) CHlpListBox();
+	iSearchResults->ConstructL(*this);
+	iSearchResults->SetObserver(this);
+	iSearchResults->MakeVisible(EFalse);
+
+	iView->SetFocus(ETrue);
+
+	ActivateL();
+	}
+
+//
+// ACCESS
+//
+
+TBool CHlpMainView::IsSearchPromptVisible() const
+	{
+	return iSearchPrompt->IsVisible();
+	}
+
+TBool CHlpMainView::IsSearchResultVisible() const
+	{
+	return iSearchResults->IsVisible();
+	}
+
+void CHlpMainView::ShowSearchPrompt(TBool aShow)
+	{
+	iSearchPrompt->MakeVisible(aShow);
+	}
+
+void CHlpMainView::MakeResultsVisible(TBool aVisible)
+	{
+	TRect rect(Rect());
+	TSize resultsSize = iSearchResults->Size();
+
+	if	(!aVisible)
+		{
+		// Make the main view rect 'full size' again
+		iView->SetRect(rect);
+		iSearchResults->ListBox()->SetFocus(EFalse);
+		iView->SetFocus(ETrue);
+		}
+	else
+		{
+		rect.iBr.iX -= resultsSize.iWidth;
+		iView->SetRect(rect);
+		iView->SetFocus(EFalse);
+		iSearchResults->ListBox()->SetFocus(ETrue);
+		}
+	iSearchResults->MakeVisible(aVisible);
+	DrawNow();
+	}
+
+//
+// FROM CCoeControl
+//
+
+void CHlpMainView::SizeChanged()
+	{
+	iView->SetRect(Rect());
+
+	TRect rect(Rect());
+	TSize KScreenSize(iCoeEnv->ScreenDevice()->SizeInPixels());
+
+	// Work out the size of the search prompt minus the inset for the left and right
+	// hand size. Kludge this a bit to make sure we allow for the size of any scrollbar
+	// (hence the *6 rather than the expected *2)
+	TSize searchPromptSize(KScreenSize.iWidth - (4*KSizeSearchPromptIndent), KSizeSearchPromptHeight);
+	iSearchPrompt->SetExtent(TPoint(KSizeSearchPromptIndent, rect.iBr.iY - KSizeSearchPromptHeight - KSizeSearchPromptIndent), searchPromptSize);
+
+	TRect resultsRect(rect);
+	resultsRect.iTl.iX = resultsRect.iBr.iX - KResultsViewWidth;
+	iSearchResults->SetRect(resultsRect);
+	}
+
+TInt CHlpMainView::CountComponentControls() const
+	{
+	return 3;
+	}
+
+CCoeControl* CHlpMainView::ComponentControl(TInt aIndex) const
+	{
+	switch (aIndex)
+		{
+	default:
+	case 0:
+		return iView;
+	case 1:
+		return iSearchPrompt;
+	case 2:
+		return iSearchResults;
+		}
+	}
+
+TKeyResponse CHlpMainView::OfferKeyEventL(const TKeyEvent& aKeyEvent,TEventCode aType)
+	{
+	// Send cursors to the rich text edwin (kludgy)
+	if	(aKeyEvent.iCode >= EKeyPageUp && aKeyEvent.iCode <= EKeyDownArrow)
+		{
+		if	(iView->IsFocused())
+			return iView->OfferKeyEventL(aKeyEvent, aType);
+		else
+			return iSearchResults->OfferKeyEventL(aKeyEvent, aType);
+		}
+	else
+		{
+		if	(!iSearchPrompt->IsVisible() && aType == EEventKey)
+			{
+			iSearchPrompt->MakeVisible(ETrue);
+			iSearchPrompt->SetFocus(ETrue);
+			}
+		return iSearchPrompt->OfferKeyEventL(aKeyEvent, aType);
+		}
+	}
+
+//
+// FROM MCoeControlObserver
+//
+
+void CHlpMainView::HandleControlEventL(CCoeControl* aControl, TCoeEvent aEventType)
+	{
+	if	(aControl == iSearchPrompt && aEventType == EEventStateChanged)
+		{
+		// Action the search
+		DoSearchL();
+
+		// Update the list of topics available for this category
+		iSearchPrompt->MakeVisible(EFalse);
+
+		// Reset the search prompt
+		iSearchPrompt->ResetSearchL();
+		}
+	else if (aControl == iSearchResults && aEventType == EEventRequestExit)
+		{
+		// Finished with results
+		MakeResultsVisible(EFalse);
+		}
+	else if (aControl == iSearchResults && aEventType == EEventStateChanged)
+		{
+		// Display the selected topic that the user searched for
+		iView->UpdateEdwinL(iSearchResults->HelpItemL());
+		}
+	}
+
+//
+// FROM MHlpModelObserver
+//
+
+void CHlpMainView::HandleModelEventL(TInt aEvent)
+	{
+	iLastHelpModelResponse = aEvent;
+
+	if (aEvent == ESearchListAvailable || aEvent == ESearchListNoneFound)
+		{
+		iEikonEnv->BusyMsgCancel();
+
+		// This is a special case which is initiated by full text searching...
+		iModel.SetObserver(iView);
+
+		// Now populate the search results listbox.
+		if	(iLastHelpModelResponse == ESearchListNoneFound)
+			{
+			iEikonEnv->InfoMsg(R_HELPVIEW_TEXT_NO_SEARCH_RESULTS);
+			return;
+			}
+
+		// Get a topic list (because some were found)
+		CHlpList* list = CHlpList::NewL();
+		iModel.LoadListL(list);
+		iSearchResults->PopulateListBoxL(list); // takes ownership
+		MakeResultsVisible(ETrue); // show results
+		}
+	}
+
+//
+// INTERNAL
+//
+
+void CHlpMainView::DoSearchL()
+	{
+	HBufC* searchSpec = iSearchPrompt->SearchTextLC();
+	__ASSERT_DEBUG(searchSpec, Panic(EHlpViewPanicNoSearchSpec));
+
+	// Set this class as the observer (kludge)
+	iModel.SetObserver(this);
+
+	// Request a search
+	iModel.SearchL(EFullTextSearch, searchSpec); // Asynch...
+	iEikonEnv->BusyMsgL(R_HELPVIEW_TEXT_SEARCHING, 0);
+
+	CleanupStack::PopAndDestroy(); // searchSpec
+	}
+
+
+
+