Commits

Anonymous committed 22b2879

DEV-35039 Viewer 2.0 Help System - Viewer Development

svn merge -r134800:134805 svn+ssh://svn.lindenlab.com/svn/linden/branches/viewer2help-3

Comments (0)

Files changed (48)

indra/llui/CMakeLists.txt

     llfocusmgr.h
     llfunctorregistry.h
     llhandle.h
-    llhtmlhelp.h
+    llhelp.h
     lliconctrl.h
     llkeywords.h
     lllayoutstack.h

indra/llui/llbutton.cpp

 #include "llstring.h"
 
 // Project includes
-#include "llhtmlhelp.h"
 #include "llkeyboard.h"
 #include "llui.h"
 #include "lluiconstants.h"
 #include "llfloaterreg.h"
 #include "llfocusmgr.h"
 #include "llwindow.h"
+#include "llnotifications.h"
 #include "llrender.h"
 #include "lluictrlfactory.h"
+#include "llhelp.h"
 
 static LLDefaultChildRegistry::Register<LLButton> r("button");
 
 	mouse_held_callback("mouse_held_callback"),
 	is_toggle("is_toggle", false),
 	scale_image("scale_image", true),
-	help_url("help_url"),
 	hover_glow_amount("hover_glow_amount"),
 	commit_on_return("commit_on_return", true),
 	picture_style("picture_style", false)
 	
 	mMouseDownTimer.stop();
 
-	if (p.help_url.isProvided())
-	{
-		setHelpURLCallback(p.help_url);
-	}
-
 	// if custom unselected button image provided...
 	if (p.image_unselected != default_params.image_unselected)
 	{
 	}
 }
 
-void clicked_help(void* data)
-{
-	LLButton* self = (LLButton*)data;
-	if (!self) return;
-	
-	if (!LLUI::sHtmlHelp)
-	{
-		return;
-	}
-	
-	LLUI::sHtmlHelp->show(self->getHelpURL());
-}
-
-void LLButton::setHelpURLCallback(const std::string &help_url)
-{
-	mHelpURL = help_url;
-	setClickedCallback(clicked_help,this);
-}
 
 // static
 void LLButton::toggleFloaterAndSetToggleState(LLUICtrl* ctrl, const LLSD& sdname)
 	button->setClickedCallback(boost::bind(&LLFloaterReg::toggleFloaterInstance, sdname));
 }
 
+// static
+void LLButton::showHelp(LLUICtrl* ctrl, const LLSD& sdname)
+{
+	// search back through the button's parents for a panel
+	// with a help_topic string defined
+	std::string help_topic;
+	if (LLUI::sHelpImpl &&
+	    ctrl->findHelpTopic(help_topic))
+	{
+		LLUI::sHelpImpl->showTopic(help_topic);
+		return; // success
+	}
+
+	// display an error if we can't find a help_topic string.
+	// fix this by adding a help_topic attribute to the xui file
+	LLNotifications::instance().add("UnableToFindHelpTopic");
+}
+
 void LLButton::resetMouseDownTimer()
 {
 	mMouseDownTimer.stop();

indra/llui/llbutton.h

 								commit_on_return,
 								picture_style;      //if true, don't display label
 		
-		Optional<std::string>		help_url;
 		Optional<F32>				hover_glow_amount;
 		Optional<TimeIntervalParam>	held_down_delay;
 
 	void			setCommitOnReturn(BOOL commit) { mCommitOnReturn = commit; }
 	BOOL			getCommitOnReturn() const { return mCommitOnReturn; }
 
-	void			setHelpURLCallback(const std::string &help_url);
-	const std::string&	getHelpURL() const { return mHelpURL; }
-
 	static void		onHeldDown(void *userdata);  // to be called by gIdleCallbacks
 	static void		toggleFloaterAndSetToggleState(LLUICtrl* ctrl, const LLSD& sdname);
 	static void		setFloaterToggle(LLUICtrl* ctrl, const LLSD& sdname);
+	static void		showHelp(LLUICtrl* ctrl, const LLSD& sdname);
 	
 protected:
 	const LLPointer<LLUIImage>&	getImageUnselected() const	{ return mImageUnselected; }
 	BOOL						mCommitOnReturn;
 	BOOL						mFadeWhenDisabled;
 
-	std::string					mHelpURL;
-
 	LLFrameTimer				mFlashingTimer;
 };
 

indra/llui/llfloater.cpp

 #include "lltabcontainer.h"
 #include "v2math.h"
 #include "lltrans.h"
+#include "llhelp.h"
 #include "llmultifloater.h"
 
 // use this to control "jumping" behavior when Ctrl-Tabbing
 
 std::string	LLFloater::sButtonActiveImageNames[BUTTON_COUNT] = 
 {
-	"Icon_Close_Foreground",		//BUTTON_CLOSE
-	"restore.tga",	//BUTTON_RESTORE
-	"minimize.tga",	//BUTTON_MINIMIZE
-	"tearoffbox.tga",	//BUTTON_TEAR_OFF
-	"closebox.tga",		//BUTTON_EDIT
-	"Icon_Dock_Foreground",
-	"Icon_Undock_Foreground"
-};
-
-// Empty string means programmatic glow effect, achieved by
-// not setting explicit image.
-std::string	LLFloater::sButtonHoveredImageNames[BUTTON_COUNT] = 
-{
-	"",						//BUTTON_CLOSE
-	"restore_pressed.tga",	//BUTTON_RESTORE
-	"minimize_pressed.tga",	//BUTTON_MINIMIZE
-	"tearoff_pressed.tga",	//BUTTON_TEAR_OFF
-	"close_in_blue.tga",	//BUTTON_EDIT
-	"",						//BUTTON_DOCK
-	"",						//BUTTON_UNDOCK
+	"Icon_Close_Foreground",	//BUTTON_CLOSE
+	"Icon_Restore_Foreground",	//BUTTON_RESTORE
+	"Icon_Minimize_Foreground",	//BUTTON_MINIMIZE
+	"tearoffbox.tga",			//BUTTON_TEAR_OFF
+	"Icon_Dock_Foreground",		//BUTTON_DOCK
+	"Icon_Undock_Foreground",	//BUTTON_UNDOCK
+	"Icon_Help_Foreground"		//BUTTON_HELP
 };
 
 std::string	LLFloater::sButtonPressedImageNames[BUTTON_COUNT] = 
 {
-	"Icon_Close_Press",		//BUTTON_CLOSE
-	"restore_pressed.tga",	//BUTTON_RESTORE
-	"minimize_pressed.tga",	//BUTTON_MINIMIZE
-	"tearoff_pressed.tga",	//BUTTON_TEAR_OFF
-	"close_in_blue.tga",		//BUTTON_EDIT
-	"Icon_Dock_Press",
-	"Icon_Undock_Press"
+	"Icon_Close_Press",			//BUTTON_CLOSE
+	"Icon_Restore_Press",		//BUTTON_RESTORE
+	"Icon_Minimize_Press",		//BUTTON_MINIMIZE
+	"tearoff_pressed.tga",		//BUTTON_TEAR_OFF
+	"Icon_Dock_Press",			//BUTTON_DOCK
+	"Icon_Undock_Press",		//BUTTON_UNDOCK
+	"Icon_Help_Press"			//BUTTON_HELP
 };
 
 std::string	LLFloater::sButtonNames[BUTTON_COUNT] = 
 {
-	"llfloater_close_btn",	//BUTTON_CLOSE
+	"llfloater_close_btn",		//BUTTON_CLOSE
 	"llfloater_restore_btn",	//BUTTON_RESTORE
 	"llfloater_minimize_btn",	//BUTTON_MINIMIZE
 	"llfloater_tear_off_btn",	//BUTTON_TEAR_OFF
-	"llfloater_edit_btn",		//BUTTON_EDIT
-	"llfloater_dock_btn",
-	"llfloater_undock_btn"
+	"llfloater_dock_btn",		//BUTTON_DOCK
+	"llfloater_undock_btn",		//BUTTON_UNDOCK
+	"llfloater_help_btn"		//BUTTON_HELP
 };
 
 std::string LLFloater::sButtonToolTips[BUTTON_COUNT];
 	"BUTTON_RESTORE",		//"Restore",	//BUTTON_RESTORE
 	"BUTTON_MINIMIZE",		//"Minimize",	//BUTTON_MINIMIZE
 	"BUTTON_TEAR_OFF",		//"Tear Off",	//BUTTON_TEAR_OFF
-	"BUTTON_EDIT",			//"Edit",		//BUTTON_EDIT
 	"BUTTON_DOCK",
-	"BUTTON_UNDOCK"
+	"BUTTON_UNDOCK",
+	"BUTTON_HELP"
 };
 
 LLFloater::click_callback LLFloater::sButtonCallbacks[BUTTON_COUNT] =
 	LLFloater::onClickMinimize, //BUTTON_RESTORE
 	LLFloater::onClickMinimize, //BUTTON_MINIMIZE
 	LLFloater::onClickTearOff,	//BUTTON_TEAR_OFF
-	LLFloater::onClickEdit,	//BUTTON_EDIT
-	LLFloater::onClickDock,
-	LLFloater::onClickDock
+	LLFloater::onClickDock,		//BUTTON_DOCK
+	LLFloater::onClickDock,		//BUTTON_UNDOCK
+	LLFloater::onClickHelp		//BUTTON_HELP
 };
 
 LLMultiFloater* LLFloater::sHostp = NULL;
-BOOL			LLFloater::sEditModeEnabled = FALSE;
 BOOL			LLFloater::sQuitting = FALSE; // Flag to prevent storing visibility controls while quitting
 LLFloater::handle_map_t	LLFloater::sFloaterMap;
 
 	mMinimized(FALSE),
 	mForeground(FALSE),
 	mFirstLook(TRUE),
-	mEditing(FALSE),
 	mButtonScale(1.0f),
 	mAutoFocus(TRUE), // automatically take focus when opened
 	mCanDock(false),
 		mButtonsEnabled[BUTTON_CLOSE] = TRUE;
 	}
 
+	// Help button: '?'
+	if ( !mHelpTopic.empty() )
+	{
+		mButtonsEnabled[BUTTON_HELP] = TRUE;
+	}
+
 	// Minimize button only for top draggers
 	if ( !mDragOnLeft && mCanMinimize )
 	{
 	applyTitle();
 }
 
-std::string LLFloater::getTitle()
+std::string LLFloater::getTitle() const
 {
 	if (mTitle.empty())
 	{
 	applyTitle();
 }
 
-std::string LLFloater::getShortTitle()
+std::string LLFloater::getShortTitle() const
 {
 	if (mShortTitle.empty())
 	{
 	}
 }
 
-
-
 BOOL LLFloater::canSnapTo(const LLView* other_view)
 {
 	if (NULL == other_view)
 		reshape( mExpandedRect.getWidth(), mExpandedRect.getHeight(), TRUE );
 	}
 	
+	// don't show the help button while minimized - it's
+	// not very useful when minimized and uses up space
+	mButtonsEnabled[BUTTON_HELP] = !minimize;
+
 	applyTitle ();
 
 	make_ui_sound("UISndWindowClose");
 	}
 }
 
-//static
-void LLFloater::setEditModeEnabled(BOOL enable)
-{
-	if (enable != sEditModeEnabled)
-	{
-		S32 count = 0;
-		for(handle_map_iter_t iter = sFloaterMap.begin(); iter != sFloaterMap.end(); ++iter)
-		{
-			LLFloater* floater = iter->second;
-			if (!floater->isDead())
-			{
-				iter->second->mButtonsEnabled[BUTTON_EDIT] = enable;
-				iter->second->updateButtons();
-			}
-			count++;
-		}
-	}
-
-	sEditModeEnabled = enable;
-}
-
-
 // static
 void LLFloater::onClickMinimize(LLFloater* self)
 {
 }
 
 // static
-void LLFloater::onClickEdit(LLFloater* self)
-{
-	if (!self)
-		return;
-	self->mEditing = self->mEditing ? FALSE : TRUE;
-}
-
-// static
 void LLFloater::onClickDock(LLFloater* self)
 {
 	if(self && self->mCanDock)
 	}
 }
 
+// static
+void LLFloater::onClickHelp( LLFloater* self )
+{
+	if (self && LLUI::sHelpImpl)
+	{
+		LLUI::sHelpImpl->showTopic(self->getHelpTopic());
+	}
+}
+
 // static 
 LLFloater* LLFloater::getClosableFloaterFromFocus()
 {
 		// Selected, no matter if hovered or not, is "pressed"
 		p.image_selected.name(sButtonPressedImageNames[i]);
 		p.image_hover_selected.name(sButtonPressedImageNames[i]);
-		// Empty string means programmatic glow effect, achieved by
-		// not setting explicit image.
-		if (sButtonHoveredImageNames[i].empty())
-		{
-			// These icons are really small, need glow amount increased
-			p.hover_glow_amount( 0.22f );
-		}
-		else
-		{
-			p.image_hover_unselected.name(sButtonHoveredImageNames[i]);
-		}
+		// Use a glow effect when the user hovers over the button
+		// These icons are really small, need glow amount increased
+		p.hover_glow_amount( 0.33f );
 		p.click_callback.function(boost::bind(sButtonCallbacks[i], this));
 		p.tab_stop(false);
 		p.follows.flags(FOLLOWS_TOP|FOLLOWS_RIGHT);

indra/llui/llfloater.h

 		BUTTON_RESTORE,
 		BUTTON_MINIMIZE,
 		BUTTON_TEAR_OFF,
-		BUTTON_EDIT,
 		BUTTON_DOCK,
 		BUTTON_UNDOCK,
+		BUTTON_HELP,
 		BUTTON_COUNT
 	};
 	
 	void			applyTitle();
 	const std::string&	getCurrentTitle() const;
 	void			setTitle( const std::string& title);
-	std::string		getTitle();
+	std::string		getTitle() const;
 	void			setShortTitle( const std::string& short_title );
-	std::string		getShortTitle();
+	std::string		getShortTitle() const;
 	void			setTitleVisible(bool visible);
 	virtual void	setMinimized(BOOL b);
 	void			moveResizeHandlesToFront();
 	static void		onClickClose(LLFloater* floater);
 	static void		onClickMinimize(LLFloater* floater);
 	static void		onClickTearOff(LLFloater* floater);
-	static void		onClickEdit(LLFloater* floater);
 	static void     onClickDock(LLFloater* floater);
+	static void		onClickHelp(LLFloater* floater);
 
 	static void		setFloaterHost(LLMultiFloater* hostp) {sHostp = hostp; }
-	static void		setEditModeEnabled(BOOL enable);
-	static BOOL		getEditModeEnabled() { return sEditModeEnabled; }
 	static LLMultiFloater* getFloaterHost() {return sHostp; }
 		
 protected:
 	
 
 	BOOL			mFirstLook;			// TRUE if the _next_ time this floater is visible will be the first time in the session that it is visible.
-	BOOL			mEditing;
 	
 	typedef std::set<LLHandle<LLFloater> > handle_set_t;
 	typedef std::set<LLHandle<LLFloater> >::iterator handle_set_iter_t;
 	bool            mDocked;
 
 	static LLMultiFloater* sHostp;
-	static BOOL		sEditModeEnabled;
 	static BOOL		sQuitting;
 	static std::string	sButtonActiveImageNames[BUTTON_COUNT];
-	// Images to use when cursor hovered over an enabled button
-	static std::string	sButtonHoveredImageNames[BUTTON_COUNT];
 	static std::string	sButtonPressedImageNames[BUTTON_COUNT];
 	static std::string	sButtonNames[BUTTON_COUNT];
 	static std::string	sButtonToolTips[BUTTON_COUNT];

indra/llui/llhelp.h

+/** 
+ * @file llhelp.h
+ * @brief Abstract interface to the Help system
+ * @author Tofu Linden
+ *
+ * $LicenseInfo:firstyear=2009&license=viewergpl$
+ * 
+ * Copyright (c) 2009, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLHELP_H
+#define LL_LLHELP_H
+
+class LLHelp
+{
+ public:
+	virtual void showTopic(const std::string &topic) = 0;
+	// return default (fallback) topic name suitable for showTopic()
+	virtual std::string defaultTopic() = 0;
+};
+
+#endif // headerguard

indra/llui/llpanel.cpp

 	strings("string"),
 	filename("filename"),
 	class_name("class"),
+	help_topic("help_topic"),
 	visible_callback("visible_callback")
 {
 	name = "panel";
 	mDefaultBtn(NULL),
 	mBorder(NULL),
 	mLabel(p.label),
+	mHelpTopic(p.help_topic),
 	mCommitCallbackRegistrar(false),
 	mEnableCallbackRegistrar(false),
 	mXMLFilename(p.filename)
 	}
 
 	setLabel(p.label());
+	setHelpTopic(p.help_topic);
 	setShape(p.rect);
 	parseFollowsFlags(p);
 

indra/llui/llpanel.h

 
 		Optional<std::string>	filename;
 		Optional<std::string>	class_name;
+		Optional<std::string>   help_topic;
 
 		Multiple<LocalizedString>	strings;
 		
 	void			updateDefaultBtn();
 	void			setLabel(const LLStringExplicit& label) { mLabel = label; }
 	std::string		getLabel() const { return mLabel; }
+	void			setHelpTopic(const std::string& help_topic) { mHelpTopic = help_topic; }
+	std::string		getHelpTopic() const { return mHelpTopic; }
 	
 	void			setCtrlsEnabled(BOOL b);
 
-
 	LLHandle<LLPanel>	getHandle() const { return mPanelHandle; }
 
 	const LLCallbackMap::map_t& getFactoryMap() const { return mFactoryMap; }
 	EnableCallbackRegistry::ScopedRegistrar mEnableCallbackRegistrar;
 	
 	commit_signal_t mVisibleSignal;		// Called when visibility changes, passes new visibility as LLSD()
+
+	std::string		mHelpTopic;         // the name of this panel's help topic to display in the Help Viewer
 	
 private:
 	LLUIColor		mBgColorAlpha;
 
 	// for setting the xml filename when building panel in context dependent cases
 	std::string		mXMLFilename;
-	
+
 }; // end class LLPanel
 
 #endif

indra/llui/llui.cpp

 /*static*/ LLUIAudioCallback LLUI::sAudioCallback = NULL;
 /*static*/ LLVector2		LLUI::sGLScaleFactor(1.f, 1.f);
 /*static*/ LLWindow*		LLUI::sWindow = NULL;
-/*static*/ LLHtmlHelp*		LLUI::sHtmlHelp = NULL;
 /*static*/ LLView*			LLUI::sRootView = NULL;
-/*static*/ BOOL				LLUI::sDirty = FALSE;
-/*static*/ LLRect			LLUI::sDirtyRect;
+/*static*/ BOOL                         LLUI::sDirty = FALSE;
+/*static*/ LLRect                       LLUI::sDirtyRect;
+/*static*/ LLHelp*			LLUI::sHelpImpl = NULL;
 /*static*/ std::vector<std::string> LLUI::sXUIPaths;
 /*static*/ LLFrameTimer		LLUI::sMouseIdleTimer;
 
 }
 
 
-void gl_draw_scaled_image_inverted(S32 x, S32 y, S32 width, S32 height, LLTexture* image, const LLColor4& color, const LLRectf& uv_rect)
-{
-	if (NULL == image)
-	{
-		llwarns << "image == NULL; aborting function" << llendl;
-		return;
-	}
-
-	LLGLSUIDefault gls_ui;
-
-	gGL.pushMatrix();
-	{
-		gGL.translatef((F32)x, (F32)y, 0.f);
-
-		gGL.getTexUnit(0)->bind(image);
-
-		gGL.color4fv(color.mV);
-		
-		gGL.begin(LLRender::QUADS);
-		{
-			gGL.texCoord2f(uv_rect.mRight, uv_rect.mBottom);
-			gGL.vertex2i(width, height );
-
-			gGL.texCoord2f(uv_rect.mLeft, uv_rect.mBottom);
-			gGL.vertex2i(0, height );
-
-			gGL.texCoord2f(uv_rect.mLeft, uv_rect.mTop);
-			gGL.vertex2i(0, 0);
-
-			gGL.texCoord2f(uv_rect.mRight, uv_rect.mTop);
-			gGL.vertex2i(width, 0);
-		}
-		gGL.end();
-	}
-	gGL.popMatrix();
-}
-
-
 void gl_stippled_line_3d( const LLVector3& start, const LLVector3& end, const LLColor4& color, F32 phase )
 {
 	phase = fmod(phase, 1.f);
 	// Button initialization callback for toggle buttons
 	LLUICtrl::CommitCallbackRegistry::defaultRegistrar().add("Button.SetFloaterToggle", boost::bind(&LLButton::setFloaterToggle, _1, _2));
 	
+	// Display the help topic for the current context
+	LLUICtrl::CommitCallbackRegistry::defaultRegistrar().add("Button.ShowHelp", boost::bind(&LLButton::showHelp, _1, _2));
+
 	// Currently unused, but kept for reference:
 	LLUICtrl::CommitCallbackRegistry::defaultRegistrar().add("Button.ToggleFloater", boost::bind(&LLButton::toggleFloaterAndSetToggleState, _1, _2));
 	
 		return NULL;
 }
 
-// static 
-void LLUI::setHtmlHelp(LLHtmlHelp* html_help)
-{
-	LLUI::sHtmlHelp = html_help;
-}
-
 LLControlGroup& LLUI::getControlControlGroup (const std::string& controlname)
 {
 	for (settings_map_t::iterator itor = sSettingGroups.begin();

indra/llui/llui.h

 #include "llfontgl.h"
 
 class LLColor4; 
-class LLHtmlHelp;
 class LLVector3;
 class LLVector2;
 class LLUIImage;
 class LLUUID;
 class LLWindow;
 class LLView;
+class LLHelp;
 
 // UI colors
 extern const LLColor4 UI_VERTEX_COLOR;
 void gl_draw_scaled_rotated_image(S32 x, S32 y, S32 width, S32 height, F32 degrees,LLTexture* image, const LLColor4& color = UI_VERTEX_COLOR, const LLRectf& uv_rect = LLRectf(0.f, 1.f, 1.f, 0.f));
 void gl_draw_scaled_image_with_border(S32 x, S32 y, S32 border_width, S32 border_height, S32 width, S32 height, LLTexture* image, const LLColor4 &color, BOOL solid_color = FALSE, const LLRectf& uv_rect = LLRectf(0.f, 1.f, 1.f, 0.f));
 void gl_draw_scaled_image_with_border(S32 x, S32 y, S32 width, S32 height, LLTexture* image, const LLColor4 &color, BOOL solid_color = FALSE, const LLRectf& uv_rect = LLRectf(0.f, 1.f, 1.f, 0.f), const LLRectf& scale_rect = LLRectf(0.f, 1.f, 1.f, 0.f));
-// Flip vertical, used for LLFloaterHTML
-void gl_draw_scaled_image_inverted(S32 x, S32 y, S32 width, S32 height, LLTexture* image, const LLColor4& color = UI_VERTEX_COLOR, const LLRectf& uv_rect = LLRectf(0.f, 1.f, 1.f, 0.f));
 
 void gl_rect_2d_xor(S32 left, S32 top, S32 right, S32 bottom);
 void gl_stippled_line_3d( const LLVector3& start, const LLVector3& end, const LLColor4& color, F32 phase = 0.f ); 
 	static void glPointToScreen(S32 gl_x, S32 gl_y, S32 *screen_x, S32 *screen_y);
 	static void screenRectToGL(const LLRect& screen, LLRect *gl);
 	static void glRectToScreen(const LLRect& gl, LLRect *screen);
-	static void setHtmlHelp(LLHtmlHelp* html_help);
 	// Returns the control group containing the control name, or the default group
 	static LLControlGroup& getControlControlGroup (const std::string& controlname);
 	static F32 getMouseIdleTime() { return sMouseIdleTimer.getElapsedTimeF32(); }
 	static LLUIAudioCallback sAudioCallback;
 	static LLVector2		sGLScaleFactor;
 	static LLWindow*		sWindow;
-	static LLHtmlHelp*		sHtmlHelp;
 	static LLView*			sRootView;
+	static LLHelp*			sHelpImpl;
 private:
 	static LLImageProviderInterface* sImageProvider;
 	static std::vector<std::string> sXUIPaths;

indra/llui/lluictrl.cpp

 	return NULL;
 }
 
+bool LLUICtrl::findHelpTopic(std::string& help_topic_out)
+{
+	LLUICtrl* ctrl = this;
+
+	// search back through the control's parents for a panel
+	// with a help_topic string defined
+	while (ctrl)
+	{
+		LLPanel *panel = dynamic_cast<LLPanel *>(ctrl);
+		if (panel && !panel->getHelpTopic().empty())
+		{
+			help_topic_out = panel->getHelpTopic();
+			return true; // success
+		}
+		
+		ctrl = ctrl->getParentUICtrl();
+	}
+
+	return false; // no help topic found
+}
+
 // *TODO: Deprecate; for backwards compatability only:
 boost::signals2::connection LLUICtrl::setCommitCallback( boost::function<void (LLUICtrl*,void*)> cb, void* data)
 {

indra/llui/lluictrl.h

 
 	LLUICtrl*		getParentUICtrl() const;
 
+	// return true if help topic found by crawling through parents -
+	// topic then put in help_topic_out
+	bool                    findHelpTopic(std::string& help_topic_out);
+
 	boost::signals2::connection setCommitCallback( const commit_signal_t::slot_type& cb ) { return mCommitSignal.connect(cb); }
 	boost::signals2::connection setValidateCallback( const enable_signal_t::slot_type& cb ) { return mValidateSignal.connect(cb); }
 

indra/llui/llurlaction.cpp

 		LLView::getWindow()->copyTextToClipboard(utf8str_to_wstring(match.getLabel()));
 	}	
 }
-

indra/newview/CMakeLists.txt

     llfloatergroups.cpp
     llfloaterhandler.cpp
     llfloaterhardwaresettings.cpp
-    llfloaterhtmlcurrency.cpp
+    llfloaterhelpbrowser.cpp
     llfloatermediabrowser.cpp
-    llfloaterhtmlsimple.cpp
     llfloaterhud.cpp
     llfloaterimagepreview.cpp
     llfloaterinspect.cpp
     llviewerfloaterreg.cpp
     llviewergenericmessage.cpp
     llviewergesture.cpp    
+    llviewerhelp.cpp
+    llviewerhelputil.cpp
     llviewerinventory.cpp
     llviewerjointattachment.cpp
     llviewerjoint.cpp
     llfloatergroups.h
     llfloaterhandler.h
     llfloaterhardwaresettings.h
-    llfloaterhtmlcurrency.h
+    llfloaterhelpbrowser.h
     llfloatermediabrowser.h
-    llfloaterhtmlsimple.h
     llfloaterhud.h
     llfloaterimagepreview.h
     llfloaterinspect.h
     llviewerfloaterreg.h
     llviewergenericmessage.h
     llviewergesture.h    
+    llviewerhelp.h
     llviewerinventory.h
     llviewerjoint.h
     llviewerjointattachment.h
 include(LLAddBuildTest)
 SET(viewer_TEST_SOURCE_FILES
   llagentaccess.cpp
+  llviewerhelputil.cpp
   )
 set_source_files_properties(
   ${viewer_TEST_SOURCE_FILES}

indra/newview/app_settings/settings.xml

       <string>S32</string>
       <key>Value</key>
       <integer>400</integer>
-    </map>  
-    <key>HelpHomeURL</key>
-    <map>
-      <key>Comment</key>
-      <string>URL of initial help page</string>
-      <key>Persist</key>
-      <integer>1</integer>
-      <key>Type</key>
-      <string>String</string>
-      <key>Value</key>
-      <string>help/index.html</string>
-    </map>
-    <key>HelpLastVisitedURL</key>
-    <map>
-      <key>Comment</key>
-      <string>URL of last help page, will be shown next time help is accessed</string>
-      <key>Persist</key>
-      <integer>1</integer>
-      <key>Type</key>
-      <string>String</string>
-      <key>Value</key>
-      <string>help/index.html</string>
+    </map>
+    <key>HelpUseLocal</key>
+    <map>
+      <key>Comment</key>
+      <string>If set, always use this for help: skins/default/html/[LANGUAGE]/help-offline/index.html</string>
+      <key>Persist</key>
+      <integer>0</integer>
+      <key>Type</key>
+      <string>Boolean</string>
+      <key>Value</key>
+      <integer>0</integer>
+    </map>
+    <key>HelpURLFormat</key>
+    <map>
+      <key>Comment</key>
+      <string>URL pattern for help page; arguments will be encoded; see llviewerhelp.cpp:buildHelpURL for arguments</string>
+      <key>Persist</key>
+      <integer>0</integer>
+      <key>Type</key>
+      <string>String</string>
+      <key>Value</key>
+      <string>http://www.google.com/search?q=site%3Awiki.secondlife.com+[TOPIC]&amp;ignore_channel=[CHANNEL]&amp;ignore_version=[VERSION]&amp;ignore_os=[OS]&amp;ignore_language=[LANGUAGE]&amp;ignore_version_major=[VERSION_MAJOR]&amp;ignore_version_minor=[VERSION_MINOR]&amp;ignore_version_patch=[VERSION_PATCH]&amp;ignore_version_build=[VERSION_BUILD]</string>
     </map>
     <key>HighResSnapshot</key>
     <map>

indra/newview/llappviewer.cpp

 #include "llviewerobjectlist.h"
 #include "llworldmap.h"
 #include "llmutelist.h"
+#include "llviewerhelp.h"
 #include "lluicolortable.h"
 #include "llurldispatcher.h"
 #include "llurlhistory.h"
 	mNumSessions++;
 	gSavedSettings.setS32("NumSessions", mNumSessions);
 
-	gSavedSettings.setString("HelpLastVisitedURL",gSavedSettings.getString("HelpHomeURL"));
-
 	if (gSavedSettings.getBOOL("VerboseLogs"))
 	{
 		LLError::setPrintLocation(true);
 	LLUrlAction::setOpenURLExternalCallback(&LLWeb::loadURLExternal);
 	LLUrlAction::setExecuteSLURLCallback(&LLURLDispatcher::dispatchFromTextEditor);
 
+	// Let code in llui access the viewer help floater
+	LLUI::sHelpImpl = LLViewerHelp::getInstance();
+
 	// Set the link color for any Urls in text fields
 	LLTextBase::setLinkColor( LLUIColorTable::instance().getColor("HTMLLinkColor") );
 

indra/newview/llfloaterchat.cpp

 #include "lllogchat.h"
 #include "lltexteditor.h"
 #include "lltextparser.h"
-#include "llfloaterhtml.h"
 #include "llweb.h"
 #include "llstylemap.h"
 

indra/newview/llfloaterhelpbrowser.cpp

+/** 
+ * @file llfloaterhelpbrowser.cpp
+ * @brief HTML Help floater - uses embedded web browser control
+ *
+ * $LicenseInfo:firstyear=2006&license=viewergpl$
+ * 
+ * Copyright (c) 2006-2009, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "llfloaterhelpbrowser.h"
+
+#include "llfloaterreg.h"
+#include "llpluginclassmedia.h"
+#include "llmediactrl.h"
+#include "llviewerwindow.h"
+#include "llviewercontrol.h"
+#include "llweb.h"
+#include "llui.h"
+
+#include "llurlhistory.h"
+#include "llmediactrl.h"
+#include "llviewermedia.h"
+
+
+LLFloaterHelpBrowser::LLFloaterHelpBrowser(const LLSD& key)
+	: LLFloater(key)
+{
+	// really really destroy the help browser when it's closed, it'll be recreated.
+	// *TODO: when onClose() is resurrected as a virtual, this bind can go away.
+	mCloseSignal.connect(boost::bind(&LLFloaterHelpBrowser::onClose, this));
+}
+
+BOOL LLFloaterHelpBrowser::postBuild()
+{
+	mBrowser = getChild<LLMediaCtrl>("browser");
+	mBrowser->addObserver(this);
+
+	childSetAction("open_browser", onClickOpenWebBrowser, this);
+
+	buildURLHistory();
+	return TRUE;
+}
+
+void LLFloaterHelpBrowser::buildURLHistory()
+{
+	// Get all of the entries in the "browser" collection
+	LLSD browser_history = LLURLHistory::getURLHistory("browser");
+
+	// initialize URL history in the plugin
+	mBrowser->getMediaPlugin()->initializeUrlHistory(browser_history);
+}
+
+void LLFloaterHelpBrowser::onClose()
+{
+	destroy(); // really destroy this dialog on closure, it's relatively heavyweight.
+}
+
+void LLFloaterHelpBrowser::handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event)
+{
+	if(event == MEDIA_EVENT_LOCATION_CHANGED)
+	{
+		setCurrentURL(self->getLocation());
+	}
+	else if(event == MEDIA_EVENT_NAVIGATE_COMPLETE)
+	{
+		// nothing yet
+	}
+}
+
+void LLFloaterHelpBrowser::setCurrentURL(const std::string& url)
+{
+	mCurrentURL = url;
+
+	// redirects will navigate momentarily to about:blank, don't add to history
+	if (mCurrentURL != "about:blank")
+	{
+		// Serialize url history
+		LLURLHistory::removeURL("browser", mCurrentURL);
+		LLURLHistory::addURL("browser", mCurrentURL);
+	}
+}
+
+//static 
+void LLFloaterHelpBrowser::onClickClose(void* user_data)
+{
+	LLFloaterHelpBrowser* self = (LLFloaterHelpBrowser*)user_data;
+
+	self->closeFloater();
+}
+
+//static 
+void LLFloaterHelpBrowser::onClickOpenWebBrowser(void* user_data)
+{
+	LLFloaterHelpBrowser* self = (LLFloaterHelpBrowser*)user_data;
+
+	std::string url = self->mCurrentURL.empty() ? 
+		self->mBrowser->getHomePageUrl() :
+		self->mCurrentURL;
+	LLWeb::loadURLExternal(url);
+}
+
+void LLFloaterHelpBrowser::openMedia(const std::string& media_url)
+{
+	mBrowser->setHomePageUrl(media_url);
+	//mBrowser->navigateTo("data:text/html;charset=utf-8,I'd really love to be going to:<br><b>" + media_url + "</b>"); // tofu HACK for debugging =:)
+	mBrowser->navigateTo(media_url);
+	setCurrentURL(media_url);
+}
+
+void LLFloaterHelpBrowser::navigateToLocalPage( const std::string& subdir, const std::string& filename_in )
+{
+	mBrowser->navigateToLocalPage(subdir, filename_in);
+}

indra/newview/llfloaterhelpbrowser.h

+/** 
+ * @file llfloatermediabrowser.h
+ * @brief HTML Help floater - uses embedded web browser control
+ *
+ * $LicenseInfo:firstyear=2006&license=viewergpl$
+ * 
+ * Copyright (c) 2006-2009, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLFLOATERHELPBROWSER_H
+#define LL_LLFLOATERHELPBROWSER_H
+
+#include "llfloater.h"
+#include "llmediactrl.h"
+
+
+class LLMediaCtrl;
+
+class LLFloaterHelpBrowser : 
+	public LLFloater, 
+	public LLViewerMediaObserver
+{
+ public:
+	LLFloaterHelpBrowser(const LLSD& key);
+
+	/*virtual*/ BOOL postBuild();
+	void onClose();
+
+	// inherited from LLViewerMediaObserver
+	/*virtual*/ void handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event);
+
+	void openMedia(const std::string& media_url);
+
+	void navigateToLocalPage( const std::string& subdir, const std::string& filename_in );
+	
+ private:
+	void buildURLHistory();
+	void setCurrentURL(const std::string& url);
+
+	static void onClickClose(void* user_data);
+	static void onClickOpenWebBrowser(void* user_data);
+
+ private:
+	LLMediaCtrl* mBrowser;
+	std::string mCurrentURL;
+};
+
+#endif  // LL_LLFLOATERHELPBROWSER_H
+

indra/newview/llfloatermediabrowser.cpp

 /** 
- * @file llfloaterhtmlhelp.cpp
- * @brief HTML Help floater - uses embedded web browser control
+ * @file llfloatermediabrowser.cpp
+ * @brief media browser floater - uses embedded media browser control
  *
  * $LicenseInfo:firstyear=2006&license=viewergpl$
  * 
 #include "llviewerprecompiledheaders.h"
 
 #include "llfloatermediabrowser.h"
-#include "llfloaterhtml.h"
 
 #include "llfloaterreg.h"
 #include "llparcel.h"
 	mBrowser->navigateTo(media_url);
 	setCurrentURL(media_url);
 }
-////////////////////////////////////////////////////////////////////////////////
-//
-
-LLViewerHtmlHelp gViewerHtmlHelp;
-
-
-////////////////////////////////////////////////////////////////////////////////
-//
-LLViewerHtmlHelp::LLViewerHtmlHelp()
-{
-
-	LLUI::setHtmlHelp(this);
-}
-
-LLViewerHtmlHelp::~LLViewerHtmlHelp()
-{
-
-	LLUI::setHtmlHelp(NULL);
-}
-
-void LLViewerHtmlHelp::show()
-{
-	show("");
-}
-
-void LLViewerHtmlHelp::show(std::string url)
-{
-	LLFloaterMediaBrowser* floater_html = dynamic_cast<LLFloaterMediaBrowser*>(LLFloaterReg::getInstance("media_browser"));
-	floater_html->setVisible(FALSE);
-
-	if (url.empty())
-	{
-		url = floater_html->getSupportURL();
-	}
-
-	if (gSavedSettings.getBOOL("UseExternalBrowser"))
-	{
-		LLSD notificationData;
-		notificationData["url"] = url;
-
-		LLNotifications::instance().add("ClickOpenF1Help", notificationData, LLSD(), onClickF1HelpLoadURL);	    
-		floater_html->closeFloater();
-	}
-	else
-	{
-		// don't wait, just do it
-		floater_html->setVisible(TRUE);
-		floater_html->openMedia(url);
-	}
-}
-
-// static 
-bool LLViewerHtmlHelp::onClickF1HelpLoadURL(const LLSD& notification, const LLSD& response)
-{
-	LLFloaterMediaBrowser* floater_html = dynamic_cast<LLFloaterMediaBrowser*>(LLFloaterReg::getInstance("media_browser"));
-	floater_html->setVisible(FALSE);
-	std::string url = floater_html->getSupportURL();
-	S32 option = LLNotification::getSelectedOption(notification, response);
-	if (option == 0)
-	{
-		LLWeb::loadURL(url);
-	}
-	floater_html->closeFloater();
-	return false;
-}
-

indra/newview/llfloatermediabrowser.h

 /** 
  * @file llfloatermediabrowser.h
- * @brief HTML Help floater - uses embedded web browser control
+ * @brief media browser floater - uses embedded media browser control
  *
  * $LicenseInfo:firstyear=2006&license=viewergpl$
  * 
 #ifndef LL_LLFLOATERMEDIABROWSER_H
 #define LL_LLFLOATERMEDIABROWSER_H
 
-#include "llhtmlhelp.h"
 #include "llfloater.h"
 #include "llmediactrl.h"
 
-class LLViewerHtmlHelp : public LLHtmlHelp
-{
-public:
-	LLViewerHtmlHelp();
-	virtual ~LLViewerHtmlHelp();
-
-	/*virtual*/ void show();
-	/*virtual*/ void show(std::string start_url);
-	void show(std::string start_url, std::string title);
-
-	static bool onClickF1HelpLoadURL(const LLSD& notification, const LLSD& response);
-
-};
 
 class LLComboBox;
 class LLMediaCtrl;
 	std::string mCurrentURL;
 };
 
-extern LLViewerHtmlHelp gViewerHtmlHelp;
-
 #endif  // LL_LLFLOATERMEDIABROWSER_H
 

indra/newview/llfloaterreporter.cpp

 /** 
  * @file llfloaterreporter.cpp
- * @brief Bug and abuse reports.
+ * @brief Abuse reports.
  *
  * $LicenseInfo:firstyear=2002&license=viewergpl$
  * 
 void LLFloaterReporter::draw()
 {
 	// this is set by a static callback sometime after the dialog is created.
-	// Only disable screenshot for abuse reports to estate owners - bug reports always
-	// allow screenshots to be taken.
+	// Only disable screenshot for abuse reports to estate owners
 	if ( mEmailToEstateOwner )
 	{
 		childSetValue("screen_check", FALSE );
 	if (f)
 	{
 		f->setReportType(report_type);
-
-		if (report_type == BUG_REPORT)
-		{
- 			LLNotifications::instance().add("HelpReportBug");
-		}
-		else
-		{
-			// popup for abuse reports is triggered elsewhere
-		}
 	}
 }
 
 	U8 category = (U8)category_sd.asInteger();
 	if (category == 0)
 	{
-		if ( mReportType != BUG_REPORT )
-		{
-			LLNotifications::instance().add("HelpReportAbuseSelectCategory");
-		}
-		else
-		{
-			LLNotifications::instance().add("HelpReportBugSelectCategory");
-		}
+		LLNotifications::instance().add("HelpReportAbuseSelectCategory");
 		return false;
 	}
 
 
 	if ( childGetText("summary_edit").empty() )
 	{
-		if ( mReportType != BUG_REPORT )
-		{
-			LLNotifications::instance().add("HelpReportAbuseSummaryEmpty");
-		}
-		else
-		{
-			LLNotifications::instance().add("HelpReportBugSummaryEmpty");
-		}
+		LLNotifications::instance().add("HelpReportAbuseSummaryEmpty");
 		return false;
 	};
 
 	if ( childGetText("details_edit") == mDefaultSummary )
 	{
-		if ( mReportType != BUG_REPORT )
-		{
-			LLNotifications::instance().add("HelpReportAbuseDetailsEmpty");
-		}
-		else
-		{
-			LLNotifications::instance().add("HelpReportBugDetailsEmpty");
-		}
+		LLNotifications::instance().add("HelpReportAbuseDetailsEmpty");
 		return false;
 	};
 	return true;

indra/newview/llfloaterreporter.h

 /** 
  * @file llfloaterreporter.h
  * @author Andrew Meadows
- * @brief Bug and abuse reports.
+ * @brief Abuse reports.
  *
  * $LicenseInfo:firstyear=2006&license=viewergpl$
  * 
 struct LLResourceData;
 
 // these flags are used to label info requests to the server
-const U32 BUG_REPORT_REQUEST 		= 0x01 << 0;
+//const U32 BUG_REPORT_REQUEST 		= 0x01 << 0; // DEPRECATED
 const U32 COMPLAINT_REPORT_REQUEST 	= 0x01 << 1;
 const U32 OBJECT_PAY_REQUEST		= 0x01 << 2;
 
 {
 	NULL_REPORT = 0,		// don't use this value anywhere
 	UNKNOWN_REPORT = 1,
-	BUG_REPORT = 2,
+	//BUG_REPORT = 2, // DEPRECATED
 	COMPLAINT_REPORT = 3,
 	CS_REQUEST_REPORT = 4
 };

indra/newview/llmediactrl.cpp

 #include "llmediactrl.h"
 
 // viewer includes
-#include "llfloaterhtml.h"
 #include "llfloaterworldmap.h"
 #include "lluictrlfactory.h"
 #include "llurldispatcher.h"
 			if ( LLStringUtil::compareInsensitive( url.substr( 0, protocol1.length() ), protocol1 ) == 0 ||
 				 LLStringUtil::compareInsensitive( url.substr( 0, protocol2.length() ), protocol2 ) == 0 )
 			{
-				// If we spawn a new LLFloaterHTML, assume we want it to
-				// follow this LLMediaCtrl's trust for whether or
-				// not to open secondlife:///app/ links. JC.
-//				const bool open_links_externally = false;
-//				LLFloaterHtml::getInstance()->show( 
-//					event_in.mStringPayload, 
-//						"Second Life Browser",
-//							open_links_externally,
-//								mTrusted);
+				llwarns << "Dead, unimplemented path that we used to send to the built-in browser long ago." << llendl;
 			}
 		}
 	}

indra/newview/llpanellogin.cpp

 #include "lluiconstants.h"
 #include "llurlsimstring.h"
 #include "llviewerbuild.h"
+#include "llviewerhelp.h"
 #include "llviewertexturelist.h"
 #include "llviewermenu.h"			// for handle_preferences()
 #include "llviewernetwork.h"
 #include "llmediactrl.h"
 #include "llrootview.h"
 
-#include "llfloatermediabrowser.h"
 #include "llfloatertos.h"
 #include "lltrans.h"
 #include "llglheaders.h"
 
 	if ( KEY_F1 == key )
 	{
-		llinfos << "Spawning HTML help window" << llendl;
-		gViewerHtmlHelp.show();
+		LLViewerHelp* vhelp = LLViewerHelp::getInstance();
+		vhelp->showTopic(vhelp->getTopicFromFocus());
 		return TRUE;
 	}
 

indra/newview/llpreviewscript.cpp

 #include "llinventorymodel.h"
 #include "llkeyboard.h"
 #include "lllineeditor.h"
+#include "llhelp.h"
 
 #include "llresmgr.h"
 #include "llscrollbar.h"
 	"        llSay(0, \"Touched.\");\n"
 	"    }\n"
 	"}\n";
-const std::string HELP_LSL_URL = "http://wiki.secondlife.com/wiki/LSL_Portal";
+const std::string HELP_LSL_PORTAL_TOPIC = "LSL_Portal";
 
 const std::string DEFAULT_SCRIPT_NAME = "New Script"; // *TODO:Translate?
 const std::string DEFAULT_SCRIPT_DESC = "(No Description)"; // *TODO:Translate?
 
 LLScriptEdCore::LLScriptEdCore(
 	const std::string& sample,
-	const std::string& help_url,
 	const LLHandle<LLFloater>& floater_handle,
 	void (*load_callback)(void*),
 	void (*save_callback)(void*, BOOL),
 	:
 	LLPanel(),
 	mSampleText(sample),
-	mHelpURL(help_url),
 	mEditor( NULL ),
 	mLoadCallback( load_callback ),
 	mSaveCallback( save_callback ),
 	menuItem = getChild<LLMenuItemCallGL>("Help...");
 	menuItem->setClickCallback(boost::bind(&LLScriptEdCore::onBtnHelp, this));
 
-	menuItem = getChild<LLMenuItemCallGL>("LSL Wiki Help...");
+	menuItem = getChild<LLMenuItemCallGL>("Keyword Help...");
 	menuItem->setClickCallback(boost::bind(&LLScriptEdCore::onBtnDynamicHelp, this));
 }
 
 			mLiveHelpTimer.stop();
 		}
 	}
-	else if (immediate)
+	else
 	{
-		setHelpPage(LLStringUtil::null);
+		if (immediate)
+		{
+			setHelpPage(LLStringUtil::null);
+		}
 	}
 }
 
 	if (!history_combo) return;
 
 	LLUIString url_string = gSavedSettings.getString("LSLHelpURL");
+
 	url_string.setArg("[LSL_STRING]", help_string);
 
 	addHelpItemToHistory(help_string);
 	return false;
 }
 
-// static 
-bool LLScriptEdCore::onHelpWebDialog(const LLSD& notification, const LLSD& response)
-{
-	S32 option = LLNotification::getSelectedOption(notification, response);
-
-	switch(option)
-	{
-	case 0:
-		LLWeb::loadURL(notification["payload"]["help_url"]);
-		break;
-	default:
-		break;
-	}
-	return false;
-}
-
 void LLScriptEdCore::onBtnHelp()
 {
-	LLSD payload;
-	payload["help_url"] = mHelpURL;
-	LLNotifications::instance().add("WebLaunchLSLGuide", LLSD(), payload, onHelpWebDialog);
+	LLUI::sHelpImpl->showTopic(HELP_LSL_PORTAL_TOPIC);
 }
 
 void LLScriptEdCore::onBtnDynamicHelp()
 {
 	LLFloater* live_help_floater = mLiveHelpHandle.get();
-	if (live_help_floater)
+	if (!live_help_floater)
 	{
-		live_help_floater->setFocus(TRUE);
-		updateDynamicHelp(TRUE);
+		live_help_floater = new LLFloater(LLSD());
+		LLUICtrlFactory::getInstance()->buildFloater(live_help_floater, "floater_lsl_guide.xml", NULL);
+		LLFloater* parent = dynamic_cast<LLFloater*>(getParent());
+		parent->addDependentFloater(live_help_floater, TRUE);
+		live_help_floater->childSetCommitCallback("lock_check", onCheckLock, this);
+		live_help_floater->childSetValue("lock_check", gSavedSettings.getBOOL("ScriptHelpFollowsCursor"));
+		live_help_floater->childSetCommitCallback("history_combo", onHelpComboCommit, this);
+		live_help_floater->childSetAction("back_btn", onClickBack, this);
+		live_help_floater->childSetAction("fwd_btn", onClickForward, this);
 
-		return;
+		LLMediaCtrl* browser = live_help_floater->getChild<LLMediaCtrl>("lsl_guide_html");
+		browser->setAlwaysRefresh(TRUE);
+
+		LLComboBox* help_combo = live_help_floater->getChild<LLComboBox>("history_combo");
+		LLKeywordToken *token;
+		LLKeywords::keyword_iterator_t token_it;
+		for (token_it = mEditor->keywordsBegin(); 
+		     token_it != mEditor->keywordsEnd(); 
+		     ++token_it)
+		{
+			token = token_it->second;
+			help_combo->add(wstring_to_utf8str(token->getToken()));
+		}
+		help_combo->sortByName();
+
+		// re-initialize help variables
+		mLastHelpToken = NULL;
+		mLiveHelpHandle = live_help_floater->getHandle();
+		mLiveHelpHistorySize = 0;
 	}
 
-	live_help_floater = new LLFloater(LLSD());
-	LLUICtrlFactory::getInstance()->buildFloater(live_help_floater, "floater_lsl_guide.xml", NULL);
-	LLFloater* parent = dynamic_cast<LLFloater*>(getParent());
-	parent->addDependentFloater(live_help_floater, TRUE);
-	live_help_floater->childSetCommitCallback("lock_check", onCheckLock, this);
-	live_help_floater->childSetValue("lock_check", gSavedSettings.getBOOL("ScriptHelpFollowsCursor"));
-	live_help_floater->childSetCommitCallback("history_combo", onHelpComboCommit, this);
-	live_help_floater->childSetAction("back_btn", onClickBack, this);
-	live_help_floater->childSetAction("fwd_btn", onClickForward, this);
+	BOOL visible = TRUE;
+	BOOL take_focus = TRUE;
+	live_help_floater->setVisible(visible);
+	live_help_floater->setFrontmost(take_focus);
 
-	LLMediaCtrl* browser = live_help_floater->getChild<LLMediaCtrl>("lsl_guide_html");
-	browser->setAlwaysRefresh(TRUE);
-
-	LLComboBox* help_combo = live_help_floater->getChild<LLComboBox>("history_combo");
-	LLKeywordToken *token;
-	LLKeywords::keyword_iterator_t token_it;
-	for (token_it = mEditor->keywordsBegin(); 
-		token_it != mEditor->keywordsEnd(); 
-		++token_it)
-	{
-		token = token_it->second;
-		help_combo->add(wstring_to_utf8str(token->getToken()));
-	}
-	help_combo->sortByName();
-
-	// re-initialize help variables
-	mLastHelpToken = NULL;
-	mLiveHelpHandle = live_help_floater->getHandle();
-	mLiveHelpHistorySize = 0;
 	updateDynamicHelp(TRUE);
 }
 
 
 	self->mScriptEd =  new LLScriptEdCore(
 								   HELLO_LSL,
-								   HELP_LSL_URL,
 								   self->getHandle(),
 								   LLPreviewLSL::onLoad,
 								   LLPreviewLSL::onSave,
 
 	self->mScriptEd =  new LLScriptEdCore(
 								   HELLO_LSL,
-								   HELP_LSL_URL,
 								   self->getHandle(),
 								   &LLLiveLSLEditor::onLoad,
 								   &LLLiveLSLEditor::onSave,

indra/newview/llpreviewscript.h

 public:
 	LLScriptEdCore(
 		const std::string& sample,
-		const std::string& help_url,
 		const LLHandle<LLFloater>& floater_handle,
 		void (*load_callback)(void* userdata),
 		void (*save_callback)(void* userdata, BOOL close_after_save),
 	bool			handleSaveChangesDialog(const LLSD& notification, const LLSD& response);
 	bool			handleReloadFromServerDialog(const LLSD& notification, const LLSD& response);
 
-	static bool		onHelpWebDialog(const LLSD& notification, const LLSD& response);
 	static void		onCheckLock(LLUICtrl*, void*);
 	static void		onHelpComboCommit(LLUICtrl* ctrl, void* userdata);
 	static void		onClickBack(void* userdata);
 
 private:
 	std::string		mSampleText;
-	std::string		mHelpURL;
 	LLTextEditor*	mEditor;
 	void			(*mLoadCallback)(void* userdata);
 	void			(*mSaveCallback)(void* userdata, BOOL close_after_save);
 	void*			mUserdata;
 	LLComboBox		*mFunctions;
 	BOOL			mForceClose;
-	//LLPanel*		mGuiPanel;
 	LLPanel*		mCodePanel;
 	LLScrollListCtrl* mErrorList;
 	LLDynamicArray<LLEntryAndEdCore*> mBridges;

indra/newview/llstartup.cpp

 				LLStartUp::deletePasswordFromDisk();
 			}
 
+			// this is the base used to construct help URLs
+			text = LLUserAuth::getInstance()->getResponse("help_url_format");
+			if (!text.empty())
+			{
+				// replace the default help URL format
+				gSavedSettings.setString("HelpURLFormat",text);
+				
+				// don't fall back to Nebraska's pre-connection static help
+				gSavedSettings.setBOOL("HelpUseLocal", false);
+			}
+			
 			// this is their actual ability to access content
 			text = LLUserAuth::getInstance()->getResponse("agent_access_max");
 			if (!text.empty())

indra/newview/llurldispatcher.cpp

 #include "llagent.h"			// teleportViaLocation()
 #include "llcommandhandler.h"
 #include "llfloaterdirectory.h"
-#include "llfloatermediabrowser.h"
+#include "llfloaterhelpbrowser.h"
 #include "llfloaterreg.h"
 #include "llfloaterurldisplay.h"
 #include "llfloaterworldmap.h"
 									   bool trusted_browser)
 {
 	if (url.empty()) return false;
-	if (dispatchHelp(url, right_mouse)) return true;
+	//if (dispatchHelp(url, right_mouse)) return true;
 	if (dispatchApp(url, right_mouse, web, trusted_browser)) return true;
 	if (dispatchRegion(url, right_mouse)) return true;
 
 }
 
 // static
-bool LLURLDispatcherImpl::dispatchHelp(const std::string& url, bool right_mouse)
-{
-#if LL_LIBXUL_ENABLED
-	if (LLSLURL::isURLHelp(url))
-	{
-		gViewerHtmlHelp.show();
-		return true;
-	}
-#endif
-	return false;
-}
-
-// static
 bool LLURLDispatcherImpl::dispatchApp(const std::string& url, 
 									  bool right_mouse,
 									  LLMediaCtrl* web,

indra/newview/llviewerfloaterreg.cpp

 #include "llfloatergodtools.h"
 #include "llfloatergroups.h"
 #include "llfloaterhardwaresettings.h"
-#include "llfloaterhtmlcurrency.h"
+#include "llfloaterhelpbrowser.h"
 #include "llfloatermediabrowser.h"
 #include "llfloaterhud.h"
 #include "llfloaterimagepreview.h"
 	LLFloaterReg::add("god_tools", "floater_god_tools.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterGodTools>);
 	LLFloaterReg::add("group_picker", "floater_choose_group.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterGroupPicker>);
 
+	LLFloaterReg::add("help_browser", "floater_help_browser.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterHelpBrowser>);	
 	LLFloaterReg::add("hud", "floater_hud.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterHUD>);
-	LLFloaterReg::add("html_simple", "floater_html_simple.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterHtmlSimple>);
 
 	LLFloaterReg::add("impanel", "floater_im_session.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLIMFloater>);
 	LLFloaterReg::add("inventory", "floater_inventory.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterInventory>);
 	
 	// debug use only
 	LLFloaterReg::add("media_remote_ctrl", "floater_media_remote.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterMediaRemoteCtrl>);
-	
-	// Untested / dangerous - not for release
-#if !LL_RELEASE_FOR_DOWNLOAD
-	LLFloaterReg::add("buy_currency_html", "floater_html_simple.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterHtmlCurrency>);
-#endif
 
 	LLFloaterReg::registerControlVariables(); // Make sure visibility and rect controls get preserved when saving
 }

indra/newview/llviewerhelp.cpp

+/** 
+ * @file llviewerhelp.cpp
+ * @brief Utility functions for the Help system
+ * @author Tofu Linden
+ *
+ * $LicenseInfo:firstyear=2009&license=viewergpl$
+ * 
+ * Copyright (c) 2009, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "llfloaterhelpbrowser.h"
+#include "llfloaterreg.h"
+#include "llfocusmgr.h"
+#include "llviewercontrol.h"
+#include "llversionviewer.h"
+#include "llappviewer.h"
+
+#include "llviewerhelputil.h"
+#include "llviewerhelp.h"
+
+
+//////////////////////////////
+// implement LLHelp interface
+
+void LLViewerHelp::showTopic(const std::string &topic)
+{
+	showHelp();
+	
+	if( gSavedSettings.getBOOL("HelpUseLocal") )
+	{
+		LLFloaterHelpBrowser* helpbrowser = dynamic_cast<LLFloaterHelpBrowser*>(LLFloaterReg::getInstance("help_browser"));
+		helpbrowser->navigateToLocalPage( "help-offline" , "index.html" );
+	}
+	else 
+	{
+		const LLOSInfo& osinfo = LLAppViewer::instance()->getOSInfo();
+		std::string helpURL = LLViewerHelpUtil::buildHelpURL( topic, gSavedSettings, osinfo );
+		setRawURL( helpURL );
+	}
+}
+
+std::string LLViewerHelp::defaultTopic()
+{
+	// *hack: to be done properly
+	return "this_is_fallbacktopic";
+}
+
+//////////////////////////////
+// our own interfaces
+
+std::string LLViewerHelp::getTopicFromFocus()
+{
+	// use UI element with viewer's keyboard focus as basis for searching
+	LLUICtrl* focused = dynamic_cast<LLUICtrl*>(gFocusMgr.getKeyboardFocus());
+
+	if (focused)
+	{
+		std::string topic;
+		if (focused->findHelpTopic(topic))
+		{
+			return topic;
+		}
+	}
+
+	// didn't find a help topic in the UI hierarchy for focused
+	// element, return the fallback topic name instead.
+	return defaultTopic();
+}
+
+// static 
+void LLViewerHelp::showHelp()
+{
+	LLFloaterHelpBrowser* helpbrowser = dynamic_cast<LLFloaterHelpBrowser*>(LLFloaterReg::getInstance("help_browser"));
+	if (helpbrowser)
+	{
+		BOOL visible = TRUE;
+		BOOL take_focus = TRUE;
+		helpbrowser->setVisible(visible);
+		helpbrowser->setFrontmost(take_focus);
+	}
+	else
+	{
+		llwarns << "Eep, help_browser floater not found" << llendl;
+	}
+}
+
+// static
+void LLViewerHelp::setRawURL(std::string url)
+{
+	LLFloaterHelpBrowser* helpbrowser = dynamic_cast<LLFloaterHelpBrowser*>(LLFloaterReg::getInstance("help_browser"));
+	if (helpbrowser)
+	{
+		helpbrowser->openMedia(url);	
+	}
+	else
+	{
+		llwarns << "Eep, help_browser floater not found" << llendl;
+	}
+}
+

indra/newview/llviewerhelp.h

+/** 
+ * @file llviewerhelp.h
+ * @brief Utility functions for the Help system
+ * @author Tofu Linden
+ *
+ * $LicenseInfo:firstyear=2009&license=viewergpl$
+ * 
+ * Copyright (c) 2009, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLVIEWERHELP_H
+#define LL_LLVIEWERHELP_H
+
+// The Help UI lives in llfloaterhelpbrowser, llviewerhelp provides a
+// layer of abstraction that protects help-system-using code from the details of
+// the Help UI floater and how help topics are converted into URLs.
+
+#include "llhelp.h" // our abstract base
+#include "llsingleton.h"
+
+class LLUICtrl;
+
+class LLViewerHelp : public LLHelp, public LLSingleton<LLViewerHelp>
+{
+	friend class LLSingleton<LLViewerHelp>;
+
+ public:
+	/// display the specified help topic in the help viewer
+	/*virtual*/ void showTopic(const std::string &topic);
+
+	/// return default (fallback) topic name suitable for showTopic()
+	/*virtual*/ std::string defaultTopic();
+
+	// return topic derived from viewer UI focus, else default topic
+	std::string getTopicFromFocus();
+
+ private:
+	static void showHelp(); // make sure help UI is visible & raised
+	static void setRawURL(std::string url); // send URL to help UI
+};
+
+#endif // header guard

indra/newview/llviewerhelputil.cpp

+/** 
+ * @file llviewerhelp.cpp
+ * @brief Utility functions for the Help system
+ * @author Soft Linden
+ *
+ * $LicenseInfo:firstyear=2009&license=viewergpl$
+ * 
+ * Copyright (c) 2009, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "llversionviewer.h"
+
+//#include "llfloaterhelpbrowser.h"
+//#include "llfloaterreg.h"
+//#include "llfocusmgr.h"
+//#include "llviewercontrol.h"
+//#include "llappviewer.h"
+
+#include "llstring.h"
+#include "lluri.h"
+#include "llsys.h"
+
+#include "llcontrol.h"
+
+#include "llviewerhelputil.h"
+
+
+//////////////////////////////////////////////
+// Build a help URL from a topic and formatter
+
+//static
+std::string LLViewerHelpUtil::helpURLEncode( const std::string &component )
+{
+	// Every character rfc3986 allows as unreserved in 2.3, minus the tilde
+	// which we may grant special meaning. Yay.
+	const char* allowed =   
+	"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+	"abcdefghijklmnopqrstuvwxyz"
+	"0123456789"
+	"-._";
+	std::string escaped = LLURI::escape(component, allowed);
+	
+	return escaped;
+}
+
+static std::string buildHelpVersion( const U32 ver_int )
+{
+	std::ostringstream ver_str;
+	ver_str << ver_int;
+	return ver_str.str(); // not encoded - numbers are rfc3986-safe
+}
+