Move the experience panel to the bottom of the editor floater

master
dolphin 2013-08-15 09:32:12 -07:00
parent 01b363ba52
commit 02b501e4dc
10 changed files with 1052 additions and 623 deletions

View File

@ -188,6 +188,7 @@ set(viewer_SOURCE_FILES
lleventnotifier.cpp
lleventpoll.cpp
llexpandabletextbox.cpp
llexperienceassociationresponder.cpp
llexternaleditor.cpp
llface.cpp
llfasttimerview.cpp
@ -773,6 +774,7 @@ set(viewer_HEADER_FILES
lleventnotifier.h
lleventpoll.h
llexpandabletextbox.h
llexperienceassociationresponder.h
llexternaleditor.h
llface.h
llfasttimerview.h

View File

@ -0,0 +1,80 @@
/**
* @file llexperienceassociationresponder.cpp
* @brief llexperienceassociationresponder implementation
*
* $LicenseInfo:firstyear=2013&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2013, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
#include "llviewerprecompiledheaders.h"
#include "llexperienceassociationresponder.h"
#include "llexperiencecache.h"
ExperienceAssociationResponder::ExperienceAssociationResponder(ExperienceAssociationResponder::callback_t callback):mCallback(callback)
{
ref();
}
void ExperienceAssociationResponder::error( U32 status, const std::string& reason )
{
LLSD msg;
msg["error"]=(LLSD::Integer)status;
msg["message"]=reason;
LL_INFOS("ExperienceAssociation") << "Failed to look up associated experience: " << status << ": " << reason << LL_ENDL;
sendResult(msg);
}
void ExperienceAssociationResponder::result( const LLSD& content )
{
if(!content.has("experience"))
{
LLSD msg;
msg["message"]="no experience";
msg["error"]=-1;
sendResult(msg);
LL_ERRS("ExperienceAssociation") << "Associated experience missing" << LL_ENDL;
}
LLExperienceCache::get(content["experience"].asUUID(), boost::bind(&ExperienceAssociationResponder::sendResult, this, _1));
/* LLLiveLSLEditor* scriptCore = LLFloaterReg::findTypedInstance<LLLiveLSLEditor>("preview_scriptedit", mParent);
if(!scriptCore)
return;
LLUUID id;
if(content.has("experience"))
{
id=content["experience"].asUUID();
}
scriptCore->setAssociatedExperience(id);*/
}
void ExperienceAssociationResponder::sendResult( const LLSD& experience )
{
mCallback(experience);
unref();
}

View File

@ -0,0 +1,53 @@
#include "llhttpclient.h"
#include "llsd.h"
/**
* @file llexperienceassociationresponder.h
* @brief llexperienceassociationresponder and related class definitions
*
* $LicenseInfo:firstyear=2013&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2013, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
#ifndef LL_LLEXPERIENCEASSOCIATIONRESPONDER_H
#define LL_LLEXPERIENCEASSOCIATIONRESPONDER_H
#include "llhttpclient.h"
#include "llsd.h"
class ExperienceAssociationResponder : public LLHTTPClient::Responder
{
public:
typedef boost::function<void(const LLSD& experience)> callback_t;
ExperienceAssociationResponder(callback_t callback);
virtual void result(const LLSD& content);
virtual void error(U32 status, const std::string& reason);
private:
void sendResult(const LLSD& experience);
callback_t mCallback;
};
#endif // LL_LLEXPERIENCEASSOCIATIONRESPONDER_H

View File

@ -87,6 +87,7 @@
#include "llviewercontrol.h"
#include "llappviewer.h"
#include "llexperiencecache.h"
#include "llexperienceassociationresponder.h"
const std::string HELLO_LSL =
"default\n"
@ -119,54 +120,23 @@ static bool have_script_upload_cap(LLUUID& object_id)
return object && (! object->getRegion()->getCapability("UpdateScriptTask").empty());
}
class ExperienceAssociationResponder : public LLHTTPClient::Responder
{
public:
ExperienceAssociationResponder(const LLUUID& parent):mParent(parent)
{
}
LLUUID mParent;
virtual void result(const LLSD& content)
{
LLLiveLSLEditor* scriptCore = LLFloaterReg::findTypedInstance<LLLiveLSLEditor>("preview_scriptedit", mParent);
if(!scriptCore)
return;
LLUUID id;
if(content.has("experience"))
{
id=content["experience"].asUUID();
}
scriptCore->setAssociatedExperience(id);
}
virtual void error(U32 status, const std::string& reason)
{
llinfos << "Failed to look up associated script: " << status << ": " << reason << llendl;
}
};
class ExperienceResponder : public LLHTTPClient::Responder
{
public:
ExperienceResponder(const LLHandle<LLScriptEdCore>& parent):mParent(parent)
ExperienceResponder(const LLHandle<LLLiveLSLEditor>& parent):mParent(parent)
{
}
LLHandle<LLScriptEdCore> mParent;
LLHandle<LLLiveLSLEditor> mParent;
virtual void result(const LLSD& content)
{
LLScriptEdCore* scriptCore = mParent.get();
if(!scriptCore)
LLLiveLSLEditor* parent = mParent.get();
if(!parent)
return;
scriptCore->setExperienceIds(content["experience_ids"]);
parent->setExperienceIds(content["experience_ids"]);
}
};
@ -426,34 +396,37 @@ LLScriptEdCore::~LLScriptEdCore()
delete mLiveFile;
}
void LLScriptEdCore::experienceChanged()
void LLLiveLSLEditor::experienceChanged()
{
if(mAssociatedExperience != mExperiences->getSelectedValue().asUUID())
if(mScriptEd->getAssociatedExperience() != mExperiences->getSelectedValue().asUUID())
{
enableSave(TRUE);
getChildView("Save_btn")->setEnabled(TRUE);
mAssociatedExperience = mExperiences->getSelectedValue().asUUID();
mScriptEd->enableSave(getIsModifiable());
//getChildView("Save_btn")->setEnabled(TRUE);
mScriptEd->setAssociatedExperience(mExperiences->getSelectedValue().asUUID());
updateExperiencePanel();
}
}
void LLScriptEdCore::onToggleExperience( LLUICtrl *ui, void* userdata )
void LLLiveLSLEditor::onToggleExperience( LLUICtrl *ui, void* userdata )
{
LLScriptEdCore* self = (LLScriptEdCore*)userdata;
LLLiveLSLEditor* self = (LLLiveLSLEditor*)userdata;
LLUUID id;
if(self->mExperienceEnabled->get())
{
if(self->mAssociatedExperience.isNull())
if(self->mScriptEd->getAssociatedExperience().isNull())
{
id=self->mExperienceIds.beginArray()->asUUID();
}
}
if(id != self->mAssociatedExperience)
if(id != self->mScriptEd->getAssociatedExperience())
{
self->enableSave(TRUE);
self->mScriptEd->enableSave(self->getIsModifiable());
}
self->setAssociatedExperience(id);
self->mScriptEd->setAssociatedExperience(id);
self->updateExperiencePanel();
}
BOOL LLScriptEdCore::postBuild()
@ -462,12 +435,6 @@ BOOL LLScriptEdCore::postBuild()
mFunctions = getChild<LLComboBox>( "Insert...");
mExperiences = getChild<LLComboBox>("Experiences...");
mExperiences->setCommitCallback(boost::bind(&LLScriptEdCore::experienceChanged, this));
mExperienceEnabled = getChild<LLCheckBoxCtrl>("enable_xp");
childSetCommitCallback("enable_xp", onToggleExperience, this);
childSetCommitCallback("Insert...", &LLScriptEdCore::onBtnInsertFunction, this);
@ -482,8 +449,6 @@ BOOL LLScriptEdCore::postBuild()
requestExperiences();
std::vector<std::string> funcs;
std::vector<std::string> tooltips;
@ -1290,18 +1255,18 @@ LLUUID LLScriptEdCore::getAssociatedExperience()const
return mAssociatedExperience;
}
void LLScriptEdCore::setExperienceIds( const LLSD& experience_ids )
void LLLiveLSLEditor::setExperienceIds( const LLSD& experience_ids )
{
mExperienceIds=experience_ids;
updateExperiencePanel();
}
void LLScriptEdCore::updateExperiencePanel()
void LLLiveLSLEditor::updateExperiencePanel()
{
BOOL editable = mEditor->getEnabled();
BOOL editable = getIsModifiable();
if(mAssociatedExperience.isNull())
if(mScriptEd->getAssociatedExperience().isNull())
{
mExperienceEnabled->set(FALSE);
mExperiences->setVisible(FALSE);
@ -1328,10 +1293,10 @@ void LLScriptEdCore::updateExperiencePanel()
}
}
void LLScriptEdCore::addExperienceInfo(const LLSD& experience, BOOL enabled)
void LLLiveLSLEditor::addExperienceInfo(const LLSD& experience, BOOL enabled)
{
LLUUID id = experience[LLExperienceCache::EXPERIENCE_ID].asUUID();
EAddPosition position = (id == mAssociatedExperience)?ADD_TOP:ADD_BOTTOM;
EAddPosition position = (id == mScriptEd->getAssociatedExperience())?ADD_TOP:ADD_BOTTOM;
LLScrollListItem* item=mExperiences->add(experience[LLExperienceCache::NAME], id, position );
if(!enabled)
{
@ -1339,20 +1304,20 @@ void LLScriptEdCore::addExperienceInfo(const LLSD& experience, BOOL enabled)
}
}
void LLScriptEdCore::buildExperienceList()
void LLLiveLSLEditor::buildExperienceList()
{
mExperiences->clear();
bool foundAssociated=false;
for(LLSD::array_const_iterator it = mExperienceIds.beginArray(); it != mExperienceIds.endArray(); ++it)
{
LLUUID id = it->asUUID();
foundAssociated |= (id == mAssociatedExperience);
LLExperienceCache::get(id, boost::bind(&LLScriptEdCore::addExperienceInfo, this, _1, TRUE));
foundAssociated |= (id == mScriptEd->getAssociatedExperience());
LLExperienceCache::get(id, boost::bind(&LLLiveLSLEditor::addExperienceInfo, this, _1, TRUE));
}
if(!foundAssociated )
{
LLExperienceCache::get(mAssociatedExperience, boost::bind(&LLScriptEdCore::addExperienceInfo, this, _1, FALSE));
LLExperienceCache::get(mScriptEd->getAssociatedExperience(), boost::bind(&LLLiveLSLEditor::addExperienceInfo, this, _1, FALSE));
}
}
@ -1361,14 +1326,13 @@ void LLScriptEdCore::buildExperienceList()
void LLScriptEdCore::setAssociatedExperience( const LLUUID& experience_id )
{
mAssociatedExperience = experience_id;
updateExperiencePanel();
}
void LLScriptEdCore::requestExperiences()
void LLLiveLSLEditor::requestExperiences()
{
if (!mEditor->getEnabled())
if (!getIsModifiable())
{
return;
}
@ -1379,7 +1343,7 @@ void LLScriptEdCore::requestExperiences()
std::string lookup_url=region->getCapability("GetCreatorExperiences");
if(!lookup_url.empty())
{
LLHTTPClient::get(lookup_url, new ExperienceResponder(getDerivedHandle<LLScriptEdCore>()));
LLHTTPClient::get(lookup_url, new ExperienceResponder(getDerivedHandle<LLLiveLSLEditor>()));
}
}
}
@ -1945,6 +1909,15 @@ BOOL LLLiveLSLEditor::postBuild()
mScriptEd->mEditor->makePristine();
mScriptEd->mEditor->setFocus(TRUE);
mExperiences = getChild<LLComboBox>("Experiences...");
mExperiences->setCommitCallback(boost::bind(&LLLiveLSLEditor::experienceChanged, this));
mExperienceEnabled = getChild<LLCheckBoxCtrl>("enable_xp");
childSetCommitCallback("enable_xp", onToggleExperience, this);
return LLPreview::postBuild();
}
@ -2078,6 +2051,8 @@ void LLLiveLSLEditor::loadAsset()
time_corrected());
mAssetStatus = PREVIEW_ASSET_LOADED;
}
requestExperiences();
}
// static
@ -2556,7 +2531,11 @@ void LLLiveLSLEditor::fetchAssociatedExperience(const LLUUID& asset_id)
LLSD fields;
fields.append("experience");
request["fields"] = fields;
LLHTTPClient::post(lookup_url, request, new ExperienceAssociationResponder(getKey()));
ExperienceAssociationResponder::callback_t f = boost::bind(&LLLiveLSLEditor::setAssociatedExperience, getDerivedHandle<LLLiveLSLEditor>(), _1);
LLHTTPClient::post(lookup_url, request, new ExperienceAssociationResponder(f));
//test me pls
}
}
}
@ -2634,10 +2613,17 @@ BOOL LLLiveLSLEditor::monoChecked() const
return FALSE;
}
void LLLiveLSLEditor::setAssociatedExperience( const LLUUID& experience_id )
void LLLiveLSLEditor::setAssociatedExperience( LLHandle<LLLiveLSLEditor> editor, const LLSD& experience )
{
if(mScriptEd)
LLLiveLSLEditor* scriptEd = editor.get();
if(scriptEd)
{
mScriptEd->setAssociatedExperience(experience_id);
LLUUID id;
if(experience.has(LLExperienceCache::EXPERIENCE_ID))
{
id=experience[LLExperienceCache::EXPERIENCE_ID].asUUID();
}
scriptEd->mScriptEd->setAssociatedExperience(id);
scriptEd->updateExperiencePanel();
}
}

View File

@ -101,19 +101,13 @@ public:
static void onBtnInsertFunction(LLUICtrl*, void*);
static void onBtnLoadFromFile(void*);
static void onBtnSaveToFile(void*);
static void onToggleExperience(LLUICtrl *ui, void* userdata);
static bool enableSaveToFileMenu(void* userdata);
static bool enableLoadFromFileMenu(void* userdata);
virtual bool hasAccelerators() const { return true; }
void addExperienceInfo( const LLSD& experience, BOOL enabled );
void setExperienceIds(const LLSD& experience_ids);
void buildExperienceList();
virtual bool hasAccelerators() const { return true; }
LLUUID getAssociatedExperience()const;
void setAssociatedExperience( const LLUUID& experience_id );
void updateExperiencePanel();
private:
void onBtnHelp();
@ -128,10 +122,6 @@ private:
void enableSave(BOOL b) {mEnableSave = b;}
void requestExperiences();
void experienceChanged();
void addAssociatedExperience(const LLSD& experience);
protected:
void deleteBridges();
void setHelpPage(const std::string& help_string);
@ -146,9 +136,7 @@ private:
void (*mSaveCallback)(void* userdata, BOOL close_after_save);
void (*mSearchReplaceCallback) (void* userdata);
void* mUserdata;
LLComboBox *mFunctions;
LLComboBox *mExperiences;
LLCheckBoxCtrl *mExperienceEnabled;
LLComboBox *mFunctions;
BOOL mForceClose;
LLPanel* mCodePanel;
LLScrollListCtrl* mErrorList;
@ -161,7 +149,6 @@ private:
BOOL mHasScriptData;
LLLiveLSLFile* mLiveFile;
LLUUID mAssociatedExperience;
LLSD mExperienceIds;
LLScriptEdContainer* mContainer; // parent view
};
@ -244,8 +231,19 @@ public:
/*virtual*/ BOOL postBuild();
void setIsNew() { mIsNew = TRUE; }
void setAssociatedExperience( const LLUUID& experience_id );
static void setAssociatedExperience( LLHandle<LLLiveLSLEditor> editor, const LLSD& experience );
static void onToggleExperience(LLUICtrl *ui, void* userdata);
void fetchAssociatedExperience(const LLUUID& asset_id);
void addExperienceInfo( const LLSD& experience, BOOL enabled );
void setExperienceIds(const LLSD& experience_ids);
void buildExperienceList();
void updateExperiencePanel();
void requestExperiences();
void experienceChanged();
void addAssociatedExperience(const LLSD& experience);
private:
virtual BOOL canClose();
@ -299,6 +297,11 @@ private:
LLCheckBoxCtrl* mMonoCheckbox;
BOOL mIsModifiable;
LLComboBox *mExperiences;
LLCheckBoxCtrl *mExperienceEnabled;
LLSD mExperienceIds;
};
#endif // LL_LLPREVIEWSCRIPT_H

View File

@ -1,71 +1,110 @@
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<floater
legacy_header_height="18"
bevel_style="none"
border_style="line"
can_resize="true"
height="580"
layout="topleft"
min_height="271"
min_width="328"
name="script ed float"
help_topic="script_ed_float"
save_rect="true"
title="SCRIPT: NEW SCRIPT"
width="508">
<floater.string
name="not_allowed">
You can not view or edit this script, since it has been set as &quot;no copy&quot;. You need full permissions to view or edit a script inside an object.
</floater.string>
<floater.string
name="script_running">
Running
</floater.string>
<floater.string
name="Title">
SCRIPT: [NAME]
</floater.string>
<panel
bevel_style="none"
legacy_header_height="18"
bevel_style="none"
border_style="line"
can_resize="true"
height="582"
layout="topleft"
min_height="271"
min_width="328"
name="script ed float"
help_topic="script_ed_float"
save_rect="true"
title="SCRIPT: NEW SCRIPT"
width="508">
<floater.string
name="not_allowed">
You can not view or edit this script, since it has been set as &quot;no copy&quot;. You need full permissions to view or edit a script inside an object.
</floater.string>
<floater.string
name="script_running">
Running
</floater.string>
<floater.string
name="Title">
SCRIPT: [NAME]
</floater.string>
<floater.string
name="experience_enabled">
Uncheck to remove the current experience
</floater.string>
<floater.string
name="no_experiences">
You are not authorized for any experiences
</floater.string>
<floater.string
name="add_experiences">
Select to add an experience
</floater.string>
<panel
bevel_style="none"
border_style="line"
follows="left|top|right|bottom"
height="522"
layout="topleft"
left="10"
name="script ed panel"
top="20"
width="497" />
<button
follows="left|bottom"
height="23"
label="Reset"
label_selected="Reset"
layout="topleft"
name="Reset"
left="10"
width="85" />
<check_box
border_style="line"
follows="left|top|right|bottom"
height="499"
layout="topleft"
left="10"
name="script ed panel"
top="16"
width="501" />
<button
follows="left|bottom"
height="23"
label="Reset"
label_selected="Reset"
layout="topleft"
name="Reset"
left="10"
width="85" />
<check_box
left_delta="90"
top_delta="3"
enabled="false"
follows="left|bottom"
font="SansSerif"
height="18"
initial_value="true"
label="Running"
layout="topleft"
name="running"
width="205" />
<check_box
enabled="false"
follows="left|bottom"
font="SansSerif"
height="18"
initial_value="true"
label="Running"
layout="topleft"
name="running"
width="205" />
<check_box
left_delta="140"
enabled="true"
follows="left|bottom"
font="SansSerif"
height="18"
initial_value="true"
label="Mono"
layout="topleft"
name="mono"
width="100" />
enabled="true"
follows="left|bottom"
font="SansSerif"
height="18"
initial_value="true"
label="Mono"
layout="topleft"
name="mono"
width="100" />
<check_box width="130"
height="21"
enabled="false"
left="9"
top_pad="10"
layout="topleft"
follows="bottom|left"
label="Use Experience:"
name="enable_xp"/>
<combo_box
label=""
top_pad="-21"
left="149"
right="467"
layout="topleft"
follows="left|bottom|right"
visible="false"
name="Experiences..."/>
<button label="&gt;"
name="view_profile"
height="23"
width="23"
right="496"
layout="topleft"
top_pad="-23"
follows="right"
visible="false"/>
</floater>

View File

@ -32,18 +32,6 @@
name="external_editor_not_set">
Select an editor by setting the environment variable LL_SCRIPT_EDITOR or the ExternalEditor setting.
</panel.string>
<panel.string
name="experience_enabled">
Uncheck to remove the current experience
</panel.string>
<panel.string
name="no_experiences">
You are not authorized for any experiences
</panel.string>
<panel.string
name="add_experiences">
Select to add an experience
</panel.string>
<menu_bar
bg_visible="false"
follows="left|top"
@ -162,7 +150,7 @@
length="1"
follows="left|top|right|bottom"
font="Monospace"
height="346"
height="369"
ignore_tab="false"
layout="topleft"
max_length="65536"
@ -217,32 +205,5 @@
right="396"
name="Edit_btn"
width="81" />
<check_box width="130"
height="21"
enabled="false"
left="0"
top="490"
layout="topleft"
follows="bottom|left"
label="Use Experience:"
name="enable_xp"/>
<combo_box
label=""
top_pad="-23"
left="135"
right="454"
layout="topleft"
follows="left|bottom|right"
visible="false"
name="Experiences..."/>
<button label="&gt;"
name="view_profile"
height="23"
width="23"
right="482"
layout="topleft"
top_pad="-23"
follows="right"
visible="false"/>
</panel>

View File

@ -1,440 +1,471 @@
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<panel
follows="all"
height="570"
layout="topleft"
name="item properties"
help_topic="item_properties"
title="Item Profile"
width="333">
<panel.string
name="unknown">
(unknown)
</panel.string>
<panel.string
name="unknown_multiple">
(unknown / multiple)
</panel.string>
<panel.string
name="public">
(public)
</panel.string>
<panel.string
name="you_can">
You can:
</panel.string>
<panel.string
name="owner_can">
Owner can:
</panel.string>
<panel.string
name="acquiredDate">
[wkday,datetime,local] [mth,datetime,local] [day,datetime,local] [hour,datetime,local]:[min,datetime,local]:[second,datetime,local] [year,datetime,local]
</panel.string>
<panel.string
name="origin_inventory">
(Inventory)
</panel.string>
<panel.string
name="origin_inworld">
(Inworld)
</panel.string>
<icon
follows="top|right"
height="18"
image_name="Lock"
layout="topleft"
right="-15"
mouse_opaque="true"
name="IconLocked"
top="8"
width="18" />
<button
follows="top|left"
height="24"
image_hover_unselected="BackButton_Over"
image_pressed="BackButton_Press"
image_unselected="BackButton_Off"
layout="topleft"
left="12"
name="back_btn"
tab_stop="false"
top="2"
width="30"
use_draw_context_alpha="false" />
<text
follows="top|left|right"
font="SansSerifHugeBold"
height="26"
layout="topleft"
left_pad="3"
name="title"
text_color="LtGray"
top="2"
use_ellipses="true"
value="Item Profile"
width="275" />
<text
follows="top|left|right"
height="13"
layout="topleft"
left="45"
name="origin"
text_color="LtGray_50"
use_ellipses="true"
value="(Inventory)"
width="275" />
<scroll_container
color="DkGray2"
follows="all"
layout="topleft"
left="9"
name="item_profile_scroll"
opaque="true"
height="493"
width="313"
top="45">
<panel
follows="left|top|right"
height="390"
help_topic=""
label=""
layout="topleft"
left="0"
name="item_profile"
top="0"
width="295">
<text
type="string"
length="1"
follows="left|top"
height="10"
layout="topleft"
left="5"
name="LabelItemNameTitle"
top="10"
width="78">
Name:
</text>
<line_editor
border_style="line"
border_thickness="1"
follows="left|top|right"
height="20"
layout="topleft"
left_delta="78"
max_length_bytes="63"
name="LabelItemName"
top_delta="0"
width="210" />
<text
type="string"
length="1"
follows="left|top"
height="10"
layout="topleft"
left="5"
name="LabelItemDescTitle"
top_pad="10"
width="78">
Description:
</text>
<line_editor
border_style="line"
border_thickness="1"
follows="left|top|right"
height="23"
layout="topleft"
left_delta="78"
max_length_bytes="127"
name="LabelItemDesc"
top_delta="-5"
width="210" />
<text
type="string"
length="1"
follows="left|top"
height="23"
layout="topleft"
left="5"
name="LabelCreatorTitle"
top_pad="10"
width="78">
Creator:
</text>
<avatar_icon
follows="top|left"
height="20"
default_icon_name="Generic_Person"
layout="topleft"
left_pad="0"
top_delta="-6"
mouse_opaque="true"
width="20" />
<text
type="string"
follows="left|right|top"
font="SansSerifSmall"
height="15"
layout="topleft"
left_pad="5"
name="LabelCreatorName"
top_delta="6"
use_ellipses="true"
width="165">
</text>
<button
follows="top|right"
height="16"
follows="all"
height="570"
layout="topleft"
name="item properties"
help_topic="item_properties"
title="Item Profile"
width="333">
<panel.string
name="no_experience">
(none)
</panel.string>
<panel.string
name="unknown">
(unknown)
</panel.string>
<panel.string
name="unknown_multiple">
(unknown / multiple)
</panel.string>
<panel.string
name="public">
(public)
</panel.string>
<panel.string
name="you_can">
You can:
</panel.string>
<panel.string
name="owner_can">
Owner can:
</panel.string>
<panel.string
name="acquiredDate">
[wkday,datetime,local] [mth,datetime,local] [day,datetime,local] [hour,datetime,local]:[min,datetime,local]:[second,datetime,local] [year,datetime,local]
</panel.string>
<panel.string
name="origin_inventory">
(Inventory)
</panel.string>
<panel.string
name="origin_inworld">
(Inworld)
</panel.string>
<icon
follows="top|right"
height="18"
image_name="Lock"
layout="topleft"
right="-15"
mouse_opaque="true"
name="IconLocked"
top="8"
width="18" />
<button
follows="top|left"
height="24"
image_hover_unselected="BackButton_Over"
image_pressed="BackButton_Press"
image_unselected="BackButton_Off"
layout="topleft"
left="12"
name="back_btn"
tab_stop="false"
top="2"
width="30"
use_draw_context_alpha="false" />
<text
follows="top|left|right"
font="SansSerifHugeBold"
height="26"
layout="topleft"
left_pad="3"
name="title"
text_color="LtGray"
top="2"
use_ellipses="true"
value="Item Profile"
width="275" />
<text
follows="top|left|right"
height="13"
layout="topleft"
left="45"
name="origin"
text_color="LtGray_50"
use_ellipses="true"
value="(Inventory)"
width="275" />
<scroll_container
color="DkGray2"
follows="all"
layout="topleft"
left="9"
name="item_profile_scroll"
opaque="true"
height="493"
width="313"
top="45">
<panel
follows="left|top|right"
height="390"
help_topic=""
label=""
layout="topleft"
left="0"
name="item_profile"
top="0"
width="295">
<text
type="string"
length="1"
follows="left|top"
height="10"
layout="topleft"
left="5"
name="LabelItemNameTitle"
top="10"
width="78">
Name:
</text>
<line_editor
border_style="line"
border_thickness="1"
follows="left|top|right"
height="20"
layout="topleft"
left_delta="78"
max_length_bytes="63"
name="LabelItemName"
top_delta="0"
width="210" />
<text
type="string"
length="1"
follows="left|top"
height="10"
layout="topleft"
left="5"
name="LabelItemDescTitle"
top_pad="10"
width="78">
Description:
</text>
<line_editor
border_style="line"
border_thickness="1"
follows="left|top|right"
height="23"
layout="topleft"
left_delta="78"
max_length_bytes="127"
name="LabelItemDesc"
top_delta="-5"
width="210" />
<text
type="string"
length="1"
follows="left|top"
height="23"
layout="topleft"
left="5"
name="LabelCreatorTitle"
top_pad="10"
width="78">
Creator:
</text>
<avatar_icon
follows="top|left"
height="20"
default_icon_name="Generic_Person"
layout="topleft"
left_pad="0"
top_delta="-6"
mouse_opaque="true"
width="20" />
<text
type="string"
follows="left|right|top"
font="SansSerifSmall"
height="15"
layout="topleft"
left_pad="5"
name="LabelCreatorName"
top_delta="6"
use_ellipses="true"
width="165">
</text>
<button
follows="top|right"
height="16"
image_selected="Inspector_I"
image_unselected="Inspector_I"
layout="topleft"
right="-5"
name="BtnCreator"
top_delta="-6"
width="16" />
<text
type="string"
length="1"
follows="left|top"
height="23"
layout="topleft"
left="5"
name="LabelOwnerTitle"
top_pad="10"
width="78">
Owner:
</text>
<avatar_icon
follows="top|left"
height="20"
default_icon_name="Generic_Person"
layout="topleft"
left_pad="0"
top_delta="-6"
mouse_opaque="true"
width="20" />
<text
type="string"
follows="left|right|top"
font="SansSerifSmall"
height="15"
layout="topleft"
left_pad="5"
name="LabelOwnerName"
top_delta="6"
use_ellipses="true"
width="165">
</text>
<button
follows="top|right"
height="16"
image_selected="Inspector_I"
image_unselected="Inspector_I"
layout="topleft"
right="-5"
name="BtnOwner"
top_delta="-3"
width="16" />
<text
type="string"
length="1"
follows="left|top"
height="23"
layout="topleft"
left="5"
name="LabelAcquiredTitle"
top_pad="10"
width="78">
Acquired:
</text>
<text
type="string"
length="1"
follows="left|top|right"
height="23"
layout="topleft"
left_delta="78"
name="LabelAcquiredDate"
top_delta="0"
width="210">
</text>
<panel
border="false"
follows="left|top|right"
layout="topleft"
mouse_opaque="false"
name="perms_inv"
left="0"
top_pad="25"
height="155"
width="313">
<text
type="string"
length="1"
left="10"
top_pad="13"
text_color="EmphasisColor"
height="15"
follows="left|top|right"
layout="topleft"
right="-5"
name="BtnCreator"
top_delta="-6"
width="16" />
<text
name="perm_modify"
width="200">
You can:
</text>
<check_box
height="18"
label="Modify"
layout="topleft"
left="20"
name="CheckOwnerModify"
top_pad="0"
width="90" />
<check_box
height="18"
label="Copy"
layout="topleft"
left_pad="0"
name="CheckOwnerCopy"
width="90" />
<check_box
height="18"
label="Transfer"
layout="topleft"
left_pad="0"
name="CheckOwnerTransfer"
width="106" />
<text
type="string"
length="1"
follows="left|top"
height="23"
height="16"
layout="topleft"
left="5"
name="LabelOwnerTitle"
top_pad="10"
width="78">
Owner:
</text>
<avatar_icon
follows="top|left"
height="20"
default_icon_name="Generic_Person"
layout="topleft"
left_pad="0"
top_delta="-6"
mouse_opaque="true"
width="20" />
<text
type="string"
follows="left|right|top"
font="SansSerifSmall"
height="15"
layout="topleft"
left_pad="5"
name="LabelOwnerName"
top_delta="6"
use_ellipses="true"
width="165">
</text>
<button
follows="top|right"
height="16"
image_selected="Inspector_I"
image_unselected="Inspector_I"
layout="topleft"
right="-5"
name="BtnOwner"
top_delta="-3"
width="16" />
<text
type="string"
length="1"
follows="left|top"
height="23"
layout="topleft"
left="5"
name="LabelAcquiredTitle"
top_pad="10"
width="78">
Acquired:
</text>
<text
type="string"
length="1"
follows="left|top|right"
height="23"
layout="topleft"
left_delta="78"
name="LabelAcquiredDate"
top_delta="0"
width="210">
</text>
<panel
border="false"
follows="left|top|right"
layout="topleft"
mouse_opaque="false"
name="perms_inv"
left="0"
top_pad="25"
height="155"
width="313">
<text
type="string"
length="1"
left="10"
top_pad="13"
text_color="EmphasisColor"
height="15"
follows="left|top|right"
layout="topleft"
name="perm_modify"
width="200">
You can:
</text>
<check_box
height="18"
label="Modify"
layout="topleft"
left="20"
name="CheckOwnerModify"
top_pad="0"
width="90" />
<check_box
height="18"
label="Copy"
layout="topleft"
left_pad="0"
name="CheckOwnerCopy"
width="90" />
<check_box
height="18"
label="Transfer"
layout="topleft"
left_pad="0"
name="CheckOwnerTransfer"
width="106" />
<text
type="string"
length="1"
follows="left|top"
height="16"
layout="topleft"
left="10"
name="AnyoneLabel"
top_pad="8"
width="100">
Anyone:
</text>
<check_box
height="18"
label="Copy"
layout="topleft"
left_pad="0"
name="CheckEveryoneCopy"
top_delta="-2"
width="150" />
<text
type="string"
length="1"
follows="left|top"
height="16"
layout="topleft"
left="10"
name="GroupLabel"
top_pad="8"
width="100">
Group:
</text>
<check_box
height="18"
label="Share"
layout="topleft"
left_pad="0"
top_delta="-2"
name="CheckShareWithGroup"
tool_tip="Allow all members of the set group to share your modify permissions for this object. You must Deed to enable role restrictions."
width="150" />
<text
type="string"
length="1"
follows="left|top"
height="16"
layout="topleft"
left="10"
name="NextOwnerLabel"
top_pad="8"
width="200"
word_wrap="true">
Next owner:
</text>
<check_box
height="18"
label="Modify"
layout="topleft"
left="20"
top_pad="0"
name="CheckNextOwnerModify"
width="90" />
<check_box
height="18"
label="Copy"
layout="topleft"
left_pad="0"
name="CheckNextOwnerCopy"
width="90" />
<check_box
height="18"
label="Transfer"
layout="topleft"
left_pad="0"
name="CheckNextOwnerTransfer"
tool_tip="Next owner can give away or resell this object"
width="106" />
</panel>
left="10"
name="AnyoneLabel"
top_pad="8"
width="100">
Anyone:
</text>
<check_box
height="18"
label="For Sale"
layout="topleft"
left="20"
name="CheckPurchase"
top_pad="20"
width="100" />
<combo_box
height="23"
left_pad="0"
layout="topleft"
follows="left|top"
name="combobox sale copy"
width="170">
<combo_box.item
label="Copy"
name="Copy"
value="Copy" />
<combo_box.item
label="Original"
name="Original"
value="Original" />
</combo_box>
<spinner
follows="left|top"
decimal_digits="0"
increment="1"
control_name="Edit Cost"
name="Edit Cost"
label="Price: L$"
label_width="75"
left="120"
width="170"
min_val="0"
height="23"
max_val="999999999"
top_pad="10"/>
</panel>
</scroll_container>
<panel
height="30"
layout="topleft"
name="button_panel"
left="5"
top_pad="0"
width="313">
<button
height="23"
label="Cancel"
layout="topleft"
name="cancel_btn"
right="-1"
width="100" />
</panel>
</panel>
height="18"
label="Copy"
layout="topleft"
left_pad="0"
name="CheckEveryoneCopy"
top_delta="-2"
width="150" />
<text
type="string"
length="1"
follows="left|top"
height="16"
layout="topleft"
left="10"
name="GroupLabel"
top_pad="8"
width="100">
Group:
</text>
<check_box
height="18"
label="Share"
layout="topleft"
left_pad="0"
top_delta="-2"
name="CheckShareWithGroup"
tool_tip="Allow all members of the set group to share your modify permissions for this object. You must Deed to enable role restrictions."
width="150" />
<text
type="string"
length="1"
follows="left|top"
height="16"
layout="topleft"
left="10"
name="NextOwnerLabel"
top_pad="8"
width="200"
word_wrap="true">
Next owner:
</text>
<check_box
height="18"
label="Modify"
layout="topleft"
left="20"
top_pad="0"
name="CheckNextOwnerModify"
width="90" />
<check_box
height="18"
label="Copy"
layout="topleft"
left_pad="0"
name="CheckNextOwnerCopy"
width="90" />
<check_box
height="18"
label="Transfer"
layout="topleft"
left_pad="0"
name="CheckNextOwnerTransfer"
tool_tip="Next owner can give away or resell this object"
width="106" />
</panel>
<check_box
height="18"
label="For Sale"
layout="topleft"
left="20"
name="CheckPurchase"
top_pad="20"
width="100" />
<combo_box
height="23"
left_pad="0"
layout="topleft"
follows="left|top"
name="combobox sale copy"
width="170">
<combo_box.item
label="Copy"
name="Copy"
value="Copy" />
<combo_box.item
label="Original"
name="Original"
value="Original" />
</combo_box>
<spinner
follows="left|top"
decimal_digits="0"
increment="1"
control_name="Edit Cost"
name="Edit Cost"
label="Price: L$"
label_width="75"
left="120"
width="170"
min_val="0"
height="23"
max_val="999999999"
top_pad="10"/>
<text
type="string"
length="1"
follows="left|top"
height="10"
layout="topleft"
left="5"
name="LabelItemExperienceTitle"
top_pad="10"
width="78">
Experience:
</text>
<text
type="string"
length="1"
follows="left|top|right"
height="10"
layout="topleft"
left_delta="78"
name="LabelItemExperience"
top_delta="0"
width="210"
>(loading)</text>
</panel>
</scroll_container>
<panel
height="30"
layout="topleft"
name="button_panel"
left="5"
top_pad="0"
width="313"
follows="top|right|left">
<button
follows="top|right"
height="23"
label="Cancel"
layout="topleft"
name="cancel_btn"
right="-1"
width="100" />
</panel>
</panel>

View File

@ -0,0 +1,271 @@
#region Using Directives
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using System.Reflection;
using System.Security.Permissions;
#endregion
namespace TestDispatchUtility
{
/// <summary>
/// Provides helper methods for working with COM IDispatch objects that have a registered type library.
/// </summary>
public static class DispatchUtility
{
#region Private Constants
private const int S_OK = 0; //From WinError.h
private const int LOCALE_SYSTEM_DEFAULT = 2 << 10; //From WinNT.h == 2048 == 0x800
#endregion
#region Public Methods
/// <summary>
/// Gets whether the specified object implements IDispatch.
/// </summary>
/// <param name="obj">An object to check.</param>
/// <returns>True if the object implements IDispatch. False otherwise.</returns>
public static bool ImplementsIDispatch(object obj)
{
bool result = obj is IDispatchInfo;
return result;
}
/// <summary>
/// Gets a Type that can be used with reflection.
/// </summary>
/// <param name="obj">An object that implements IDispatch.</param>
/// <param name="throwIfNotFound">Whether an exception should be thrown if a Type can't be obtained.</param>
/// <returns>A .NET Type that can be used with reflection.</returns>
/// <exception cref="InvalidCastException">If <paramref name="obj"/> doesn't implement IDispatch.</exception>
[SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
public static Type GetType(object obj, bool throwIfNotFound)
{
RequireReference(obj, "obj");
Type result = GetType((IDispatchInfo)obj, throwIfNotFound);
return result;
}
/// <summary>
/// Tries to get the DISPID for the requested member name.
/// </summary>
/// <param name="obj">An object that implements IDispatch.</param>
/// <param name="name">The name of a member to lookup.</param>
/// <param name="dispId">If the method returns true, this holds the DISPID on output.
/// If the method returns false, this value should be ignored.</param>
/// <returns>True if the member was found and resolved to a DISPID. False otherwise.</returns>
/// <exception cref="InvalidCastException">If <paramref name="obj"/> doesn't implement IDispatch.</exception>
[SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
public static bool TryGetDispId(object obj, string name, out int dispId)
{
RequireReference(obj, "obj");
bool result = TryGetDispId((IDispatchInfo)obj, name, out dispId);
return result;
}
/// <summary>
/// Invokes a member by DISPID.
/// </summary>
/// <param name="obj">An object that implements IDispatch.</param>
/// <param name="dispId">The DISPID of a member. This can be obtained using
/// <see cref="TryGetDispId(object, string, out int)"/>.</param>
/// <param name="args">The arguments to pass to the member.</param>
/// <returns>The member's return value.</returns>
/// <remarks>
/// This can invoke a method or a property get accessor.
/// </remarks>
public static object Invoke(object obj, int dispId, object[] args)
{
string memberName = "[DispId=" + dispId + "]";
object result = Invoke(obj, memberName, args);
return result;
}
/// <summary>
/// Invokes a member by name.
/// </summary>
/// <param name="obj">An object.</param>
/// <param name="memberName">The name of the member to invoke.</param>
/// <param name="args">The arguments to pass to the member.</param>
/// <returns>The member's return value.</returns>
/// <remarks>
/// This can invoke a method or a property get accessor.
/// </remarks>
public static object Invoke(object obj, string memberName, object[] args)
{
RequireReference(obj, "obj");
Type type = obj.GetType();
object result = type.InvokeMember(memberName, BindingFlags.InvokeMethod | BindingFlags.GetProperty,
null, obj, args, null);
return result;
}
#endregion
#region Private Methods
/// <summary>
/// Requires that the value is non-null.
/// </summary>
/// <typeparam name="T">The type of the value.</typeparam>
/// <param name="value">The value to check.</param>
/// <param name="name">The name of the value.</param>
private static void RequireReference<T>(T value, string name) where T : class
{
if (value == null)
{
throw new ArgumentNullException(name);
}
}
/// <summary>
/// Gets a Type that can be used with reflection.
/// </summary>
/// <param name="dispatch">An object that implements IDispatch.</param>
/// <param name="throwIfNotFound">Whether an exception should be thrown if a Type can't be obtained.</param>
/// <returns>A .NET Type that can be used with reflection.</returns>
private static Type GetType(IDispatchInfo dispatch, bool throwIfNotFound)
{
RequireReference(dispatch, "dispatch");
Type result = null;
int typeInfoCount;
int hr = dispatch.GetTypeInfoCount(out typeInfoCount);
if (hr == S_OK && typeInfoCount > 0)
{
// Type info isn't usually culture-aware for IDispatch, so we might as well pass
// the default locale instead of looking up the current thread's LCID each time
// (via CultureInfo.CurrentCulture.LCID).
dispatch.GetTypeInfo(0, LOCALE_SYSTEM_DEFAULT, out result);
}
if (result == null && throwIfNotFound)
{
// If the GetTypeInfoCount called failed, throw an exception for that.
Marshal.ThrowExceptionForHR(hr);
// Otherwise, throw the same exception that Type.GetType would throw.
throw new TypeLoadException();
}
return result;
}
/// <summary>
/// Tries to get the DISPID for the requested member name.
/// </summary>
/// <param name="dispatch">An object that implements IDispatch.</param>
/// <param name="name">The name of a member to lookup.</param>
/// <param name="dispId">If the method returns true, this holds the DISPID on output.
/// If the method returns false, this value should be ignored.</param>
/// <returns>True if the member was found and resolved to a DISPID. False otherwise.</returns>
private static bool TryGetDispId(IDispatchInfo dispatch, string name, out int dispId)
{
RequireReference(dispatch, "dispatch");
RequireReference(name, "name");
bool result = false;
// Members names aren't usually culture-aware for IDispatch, so we might as well
// pass the default locale instead of looking up the current thread's LCID each time
// (via CultureInfo.CurrentCulture.LCID).
Guid iidNull = Guid.Empty;
int hr = dispatch.GetDispId(ref iidNull, ref name, 1, LOCALE_SYSTEM_DEFAULT, out dispId);
const int DISP_E_UNKNOWNNAME = unchecked((int)0x80020006); //From WinError.h
const int DISPID_UNKNOWN = -1; //From OAIdl.idl
if (hr == S_OK)
{
result = true;
}
else if (hr == DISP_E_UNKNOWNNAME && dispId == DISPID_UNKNOWN)
{
// This is the only supported "error" case because it means IDispatch
// is saying it doesn't know the member we asked about.
result = false;
}
else
{
// The other documented result codes are all errors.
Marshal.ThrowExceptionForHR(hr);
}
return result;
}
#endregion
#region Private Interfaces
/// <summary>
/// A partial declaration of IDispatch used to lookup Type information and DISPIDs.
/// </summary>
/// <remarks>
/// This interface only declares the first three methods of IDispatch. It omits the
/// fourth method (Invoke) because there are already plenty of ways to do dynamic
/// invocation in .NET. But the first three methods provide dynamic type metadata
/// discovery, which .NET doesn't provide normally if you have a System.__ComObject
/// RCW instead of a strongly-typed RCW.
/// <para/>
/// Note: The original declaration of IDispatch is in OAIdl.idl.
/// </remarks>
[ComImport]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[Guid("00020400-0000-0000-C000-000000000046")]
private interface IDispatchInfo
{
/// <summary>
/// Gets the number of Types that the object provides (0 or 1).
/// </summary>
/// <param name="typeInfoCount">Returns 0 or 1 for the number of Types provided by <see cref="GetTypeInfo"/>.</param>
/// <remarks>
/// http://msdn.microsoft.com/en-us/library/da876d53-cb8a-465c-a43e-c0eb272e2a12(VS.85)
/// </remarks>
[PreserveSig]
int GetTypeInfoCount(out int typeInfoCount);
/// <summary>
/// Gets the Type information for an object if <see cref="GetTypeInfoCount"/> returned 1.
/// </summary>
/// <param name="typeInfoIndex">Must be 0.</param>
/// <param name="lcid">Typically, LOCALE_SYSTEM_DEFAULT (2048).</param>
/// <param name="typeInfo">Returns the object's Type information.</param>
/// <remarks>
/// http://msdn.microsoft.com/en-us/library/cc1ec9aa-6c40-4e70-819c-a7c6dd6b8c99(VS.85)
/// </remarks>
void GetTypeInfo(int typeInfoIndex, int lcid, [MarshalAs(UnmanagedType.CustomMarshaler,
MarshalTypeRef = typeof(System.Runtime.InteropServices.CustomMarshalers.TypeToTypeInfoMarshaler))] out Type typeInfo);
/// <summary>
/// Gets the DISPID of the specified member name.
/// </summary>
/// <param name="riid">Must be IID_NULL. Pass a copy of Guid.Empty.</param>
/// <param name="name">The name of the member to look up.</param>
/// <param name="nameCount">Must be 1.</param>
/// <param name="lcid">Typically, LOCALE_SYSTEM_DEFAULT (2048).</param>
/// <param name="dispId">If a member with the requested <paramref name="name"/>
/// is found, this returns its DISPID and the method's return value is 0.
/// If the method returns a non-zero value, then this parameter's output value is
/// undefined.</param>
/// <returns>Zero for success. Non-zero for failure.</returns>
/// <remarks>
/// http://msdn.microsoft.com/en-us/library/6f6cf233-3481-436e-8d6a-51f93bf91619(VS.85)
/// </remarks>
[PreserveSig]
int GetDispId(ref Guid riid, ref string name, int nameCount, int lcid, out int dispId);
// NOTE: The real IDispatch also has an Invoke method next, but we don't need it.
// We can invoke methods using .NET's Type.InvokeMember method with the special
// [DISPID=n] syntax for member "names", or we can get a .NET Type using GetTypeInfo
// and invoke methods on that through reflection.
// Type.InvokeMember: http://msdn.microsoft.com/en-us/library/de3dhzwy.aspx
}
#endregion
}
}

View File

@ -0,0 +1,3 @@
<?xml version="1.0"?>
<configuration>
<startup><supportedRuntime version="v2.0.50727"/></startup></configuration>