Compare commits

..

10 Commits

Author SHA1 Message Date
Cinder
f8d38cbdd0 Pull out url bases for self-docu 2015-02-24 00:31:19 -05:00
Inusaito Sayori
21c24431db Changes proposed by Cinder, thankies~ 2015-02-24 00:29:53 -05:00
Inusaito Sayori
f2a059e985 Rework HippoGridManager's parseUrl to be called after LLAppViewer::init
No more hangs~

I'm not exactly sure if this exhibits the same behavior it used to, but this doesn't matter because it hasn't worked for versions, probably since AICurl, so no one is relying on it.
It would seem to me that it needs to be called after pumps are created.
parseUrl is now public.

Also, move hippogridmanager.h into AI_UNUSED section of llxmlrpcresponder.cpp, it's part of the unused
2015-02-21 10:23:05 -05:00
Inusaito Sayori
1c4b1149e2 Don't disable selecting friends whose friend rights are yet to be updated 2015-02-19 14:35:44 -05:00
Inusaito Sayori
454be02eab Feature Request: Allow bulk edit for objects' descriptions and names
Translators need to translate the multiple_objects_selected string in floater_tools.xml
2015-02-19 14:28:50 -05:00
Inusaito Sayori
072742cba5 [Translate] Missing Strings 2015-02-18 00:08:41 -05:00
Inusaito Sayori
9812bfc25f [Translate] Redesign Text Options panel, put Translation preferences in there.
Translators, please tend panel_preferences_ascent_chat.xml accordingly.
2015-02-17 23:29:13 -05:00
Inusaito Sayori
cbc7782b3a [Translate] Introduce an option to translate IMs
If Local chat is being translated, IM translation is on by default.
IM translation can be toggled from the drop down(flyout) menu of IMs.
Option is not shown if translation is not configured.

Translators: floater_instant_message.xml and floater_instant_message_concisebuttons.xml have two new strings for you to translate.
2015-02-17 22:00:22 -05:00
Inusaito Sayori
40afac6ae0 [Translate] More work yay~
This moves checkboxes on the local chat floater into a centralized flyout
Adds persistent setting for whether or not to show muted text in local chat.

Translators: Please translate the new flyout button and the strings in floater_chat_history.xml
2015-02-16 14:49:24 -05:00
Inusaito Sayori
891457c11a Translate, with help from Sovereign (translation backend needs an update/fixing)
Add Translate Chat checkbox back to chat floater, and enable it when applicable(with showTranslationCheckbox()).
Spend the night making it compile with AICurl~
Make the links work all nice despite our old link-unfriendly UI code.
Coax UI bits into agreeing with their new environment.
Updated the links because v-d seems to still have old ones...
Adv. Chat->Translation tab added..

Guess it's your move, again, Sovereign.

This was old, so I updated it, yayyy~
2015-02-16 02:48:56 -05:00
36 changed files with 1443 additions and 366 deletions

View File

@@ -955,7 +955,6 @@ P(responderIgnore);
P(setDisplayNameResponder);
P2(simulatorFeaturesReceived, transfer_22s_connect_10s);
P2(startGroupVoteResponder, transfer_300s);
P(translationReceiver);
P(uploadModelPremissionsResponder);
P(verifiedDestinationResponder);
P(viewerChatterBoxInvitationAcceptResponder);

View File

@@ -403,6 +403,7 @@ set(viewer_SOURCE_FILES
llpanelprimmediacontrols.cpp
llpanelprofile.cpp
llpanelskins.cpp
llpaneltranslationsettings.cpp
llpanelvoicedevicesettings.cpp
llpanelvoiceeffect.cpp
llpanelvolume.cpp
@@ -482,6 +483,7 @@ set(viewer_SOURCE_FILES
lltoolselectrect.cpp
lltoolview.cpp
lltracker.cpp
lltranslate.cpp
lluploaddialog.cpp
lluploadfloaterobservers.cpp
llurl.cpp
@@ -934,6 +936,7 @@ set(viewer_HEADER_FILES
llpanelprimmediacontrols.h
llpanelprofile.h
llpanelskins.h
llpaneltranslationsettings.h
llpanelvoicedevicesettings.h
llpanelvoiceeffect.h
llpanelvolume.h

View File

@@ -16872,6 +16872,61 @@ This should be as low as possible, but too low may break functionality</string>
<key>Value</key>
<integer>1</integer>
</map>
<key>TranslateLanguage</key>
<map>
<key>Comment</key>
<string>Translate Language specifier</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>String</string>
<key>Value</key>
<string>default</string>
</map>
<key>TranslateChat</key>
<map>
<key>Comment</key>
<string>Translate incoming chat messages</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
<integer>0</integer>
</map>
<key>TranslationService</key>
<map>
<key>Comment</key>
<string>Translation API to use. (google|bing)</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>String</string>
<key>Value</key>
<string>bing</string>
</map>
<key>GoogleTranslateAPIKey</key>
<map>
<key>Comment</key>
<string>Google Translate API key</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>String</string>
<key>Value</key>
<string></string>
</map>
<key>BingTranslateAPIKey</key>
<map>
<key>Comment</key>
<string>Bing AppID to use with the Microsoft Translator API</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>String</string>
<key>Value</key>
<string></string>
</map>
<key>InterpolationTime</key>
<map>
<key>Comment</key>

View File

@@ -785,6 +785,17 @@
<key>Value</key>
<boolean>1</boolean>
</map>
<key>SinguShowMutedLocal</key>
<map>
<key>Comment</key>
<string>Show muted chat in local chat</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
<boolean>0</boolean>
</map>
<key>UseWebProfiles</key>
<map>
<key>Comment</key>

View File

@@ -41,6 +41,7 @@
#include "llradiogroup.h"
#include "lluictrlfactory.h"
#include "llviewercontrol.h"
#include "llpaneltranslationsettings.h"
#include "NACLantispam.h"
#include "lgghunspell_wrapper.h"
#include "lltrans.h"
@@ -48,9 +49,12 @@
#include "llstartup.h"
static void* createTranslationPanel(void*) { return LLPanelTranslationSettings::getInstance(); }
LLPrefsAscentChat::LLPrefsAscentChat()
{
LLUICtrlFactory::getInstance()->buildPanel(this, "panel_preferences_ascent_chat.xml");
mFactoryMap["Translation Panel"] = LLCallbackMap(createTranslationPanel, NULL);
LLUICtrlFactory::getInstance()->buildPanel(this, "panel_preferences_ascent_chat.xml", &getFactoryMap());
getChild<LLUICtrl>("SpellBase")->setCommitCallback(boost::bind(&LLPrefsAscentChat::onSpellBaseComboBoxCommit, this, _2));
getChild<LLUICtrl>("EmSpell_EditCustom")->setCommitCallback(boost::bind(&LLPrefsAscentChat::onSpellEditCustom, this));
@@ -557,5 +561,6 @@ void LLPrefsAscentChat::apply()
{
refreshValues();
refresh();
LLPanelTranslationSettings::getInstance()->apply();
}

View File

@@ -786,9 +786,6 @@ void HippoGridManager::loadFromFile()
parseFile(gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "grids_sg1.xml"), false);
// merge default grid info, if newer. Force load, if list of grids is empty.
parseFile(gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "default_grids.xml"), !mGridInfo.empty());
// merge grid info from web site, if newer. Force load, if list of grids is empty.
if (gSavedSettings.getBOOL("CheckForGridUpdates"))
parseUrl(gSavedSettings.getString("GridUpdateList"), !mGridInfo.empty());
std::string last_grid = gSavedSettings.getString("LastSelectedGrid");
if (last_grid.empty()) last_grid = gSavedSettings.getString("DefaultGrid");
@@ -796,8 +793,9 @@ void HippoGridManager::loadFromFile()
setCurrentGrid(last_grid);
}
void HippoGridManager::parseUrl(const std::string url, bool mergeIfNewer)
void HippoGridManager::parseUrl()
{
const std::string& url(gSavedSettings.getString("GridUpdateList"));
if (url.empty()) return;
llinfos << "Loading grid info from '" << url << "'." << llendl;
@@ -816,8 +814,8 @@ void HippoGridManager::parseUrl(const std::string url, bool mergeIfNewer)
return;
}
LLSD gridInfo = response["body"];
parseData(gridInfo, mergeIfNewer);
// Force load, if list of grids is empty.
parseData(response["body"], !mGridInfo.empty());
}
void HippoGridManager::parseFile(const std::string& fileName, bool mergeIfNewer)

View File

@@ -187,6 +187,8 @@ public:
return mCurrentGridChangeSignal->connect(cb);
}
void parseUrl();
private:
friend class HippoGridInfo;
std::map<std::string, HippoGridInfo*> mGridInfo;
@@ -200,7 +202,6 @@ private:
void cleanup();
void loadFromFile();
void parseFile(const std::string& fileName, bool mergeIfNewer);
void parseUrl(const std::string url, bool mergeIfNewer);
void parseData(LLSD &gridInfo, bool mergeIfNewer);
};

View File

@@ -84,12 +84,12 @@ void LFSimFeatureHandler::setSupportedFeatures()
//if (hg)
{
has_feature_or_default(mDestinationGuideURL, extras, "destination-guide-url");
mMapServerURL = extras.has("map-server-url") ? extras["map-server-url"].asString() : "";
mMapServerURL = extras.has("map-server-url") ? extras["map-server-url"].asString() : LLStringUtil::null;
has_feature_or_default(mSearchURL, extras, "search-server-url");
if (extras.has("GridName"))
{
const std::string& grid_name(extras["GridName"]);
mGridName = gHippoGridManager->getConnectedGrid()->getGridName() != grid_name ? grid_name : "";
mGridName = gHippoGridManager->getConnectedGrid()->getGridName() != grid_name ? grid_name : LLStringUtil::null;
}
}
has_feature_or_default(mSayRange, extras, "say-range");
@@ -102,7 +102,7 @@ void LFSimFeatureHandler::setSupportedFeatures()
//if (hg)
{
mDestinationGuideURL.reset();
mMapServerURL = "";
mMapServerURL = LLStringUtil::null;
mSearchURL.reset();
mGridName.reset();
}

View File

@@ -1130,6 +1130,11 @@ bool LLAppViewer::mainLoop()
joystick->setNeedsReset(true);
LLEventPump& mainloop(LLEventPumps::instance().obtain("mainloop"));
// merge grid info from web site, if newer.
if (gSavedSettings.getBOOL("CheckForGridUpdates"))
gHippoGridManager->parseUrl();
// As we do not (yet) send data on the mainloop LLEventPump that varies
// with each frame, no need to instantiate a new LLSD event object each
// time. Obviously, if that changes, just instantiate the LLSD at the

View File

@@ -60,6 +60,7 @@
#include "llparticipantlist.h"
#include "llspeakers.h"
#include "llstylemap.h"
#include "lltranslate.h"
#include "lluictrlfactory.h"
#include "llviewermessage.h"
#include "llviewertexteditor.h"
@@ -92,10 +93,9 @@ LLFloaterChat::LLFloaterChat(const LLSD& seed)
// do not automatically open singleton floaters (as result of getInstance())
LLUICtrlFactory::getInstance()->buildFloater(this, "floater_chat_history.xml", &getFactoryMap(), /*no_open =*/false);
LLTextEditor* history_editor_with_mute = getChild<LLTextEditor>("Chat History Editor with mute");
getChild<LLUICtrl>("show mutes")->setCommitCallback(boost::bind(&LLFloaterChat::onClickToggleShowMute, this, _2, getChild<LLTextEditor>("Chat History Editor"), history_editor_with_mute));
history_editor_with_mute->setVisible(false);
getChild<LLUICtrl>("chat_history_open")->setCommitCallback(boost::bind(show_log_browser, "chat", "chat"));
LLComboBox* combo = getChild<LLComboBox>("history_combo");
combo->setCommitCallback(boost::bind(&LLFloaterChat::onFlyout, this, combo, _2));
adjustDynamics(combo, true);
}
LLFloaterChat::~LLFloaterChat()
@@ -335,13 +335,36 @@ void LLFloaterChat::setHistoryCursorAndScrollToEnd()
}
}
//static
void LLFloaterChat::onClickToggleShowMute(bool show_mute, LLTextEditor* history_editor, LLTextEditor* history_editor_with_mute)
void LLFloaterChat::adjustDynamics(LLComboBox* combo, bool init)
{
history_editor->setVisible(!show_mute);
history_editor_with_mute->setVisible(show_mute);
(show_mute ? history_editor_with_mute : history_editor)->setCursorAndScrollToEnd();
bool translate(gSavedSettings.getBOOL("TranslateChat"));
bool muted(gSavedSettings.getBOOL("SinguShowMutedLocal"));
if (!init)
{
combo->remove(getString(translate ? "translate off" : "translate on"));
combo->remove(getString(muted ? "show muted text" : "hide muted text"));
}
combo->add(getString(muted ? "hide muted text" : "show muted text"), 1);
if (LLTranslate::isTranslationConfigured())
combo->add(getString(translate ? "translate on" : "translate off"), 2);
}
void LLFloaterChat::onFlyout(LLComboBox* ctrl, const LLSD& val)
{
if (val.isUndefined())
show_log_browser("chat", "chat");
else
{
LLControlVariable* control(gSavedSettings.getControl(val.asInteger() == 1 ? "SinguShowMutedLocal" : "TranslateChat"));
control->set(!control->get());
adjustDynamics(ctrl);
}
}
void LLFloaterChat::showTranslationCheckbox()
{
adjustDynamics(getChild<LLComboBox>("history_combo"));
}
// Put a line of chat in all the right places

View File

@@ -70,8 +70,10 @@ public:
static void triggerAlerts(const std::string& text);
void onClickToggleShowMute(bool show_mute, class LLTextEditor* history_editor, LLTextEditor* history_editor_with_mute);
void adjustDynamics(class LLComboBox* combo, bool init = false);
void onFlyout(LLComboBox* ctrl, const LLSD& val);
static void chatFromLogFile(LLLogChat::ELogLineType type, std::string line, void* userdata);
void showTranslationCheckbox();
static void loadHistory();
static void* createSpeakersPanel(void* data);
static void* createChatPanel(void* data);

View File

@@ -460,7 +460,9 @@ void LLPanelFriends::updateFriendItem(const LLUUID& agent_id, const LLRelationsh
itemp->getColumn(LIST_EDIT_THEIRS)->setValue(info->isRightGrantedFrom(LLRelationship::GRANT_MODIFY_OBJECTS));
// enable this item, in case it was disabled after user input
itemp->setEnabled(true);
itemp->getColumn(LIST_VISIBLE_ONLINE)->setEnabled(true);
itemp->getColumn(LIST_VISIBLE_MAP)->setEnabled(true);
itemp->getColumn(LIST_EDIT_MINE)->setEnabled(true);
mFriendsList->setNeedsSort();
@@ -960,7 +962,10 @@ void LLPanelFriends::applyRightsToFriends()
rights_updates.insert(std::make_pair(id, rights));
// disable these ui elements until response from server
// to avoid race conditions
(*itr)->setEnabled(false);
LLScrollListItem& item = *(*itr);
item.getColumn(LIST_VISIBLE_ONLINE)->setEnabled(false);
item.getColumn(LIST_VISIBLE_MAP)->setEnabled(false);
item.getColumn(LIST_EDIT_MINE)->setEnabled(false);
}
}

View File

@@ -55,6 +55,7 @@
#include "llspeakers.h"
#include "llstylemap.h"
#include "lltrans.h"
#include "lltranslate.h"
#include "lluictrlfactory.h"
#include "llviewertexteditor.h"
#include "llviewerstats.h"
@@ -296,6 +297,7 @@ LLFloaterIMPanel::LLFloaterIMPanel(
mShowSpeakersOnConnect(true),
mDing(false),
mRPMode(false),
mTranslate(false),
mTextIMPossible(true),
mCallBackEnabled(true),
mSpeakers(NULL),
@@ -349,6 +351,8 @@ LLFloaterIMPanel::LLFloaterIMPanel(
LLAvatarTracker::instance().addParticularFriendObserver(mOtherParticipantUUID, this);
LLMuteList::instance().addObserver(this);
mDing = gSavedSettings.getBOOL("LiruNewMessageSoundIMsOn");
if (LLTranslate::isTranslationConfigured())
mTranslate = gSavedSettings.getBOOL("TranslateChat");
break;
}
@@ -696,9 +700,79 @@ bool LLFloaterIMPanel::inviteToSession(const LLDynamicArray<LLUUID>& ids)
return TRUE;
}
class IMTranslationReceiver : public LLTranslate::TranslationReceiver
{
public :
IMTranslationReceiver(const std::string& from_lang, const std::string& to_lang, LLFloaterIMPanel* panel, const std::string& msg, LLColor4 color, bool log, const LLUUID& source, const std::string& name, bool irc) : LLTranslate::TranslationReceiver(from_lang, to_lang),
mPanel(panel), mMsg(msg), mColor(color), mLog(log), mSource(source), mName(name), mIRC(irc)
{
}
static boost::intrusive_ptr<IMTranslationReceiver> build(const std::string& from_lang, const std::string& to_lang, LLFloaterIMPanel* panel, const std::string& msg, LLColor4 color, bool log, const LLUUID& source, const std::string& name, bool irc)
{
return boost::intrusive_ptr<IMTranslationReceiver>(new IMTranslationReceiver(from_lang, to_lang, panel, msg, color, log, source, name, irc));
}
protected:
void handleResponse(const std::string& translation, const std::string& detected_language)
{
// filter out non-interesting responses
if (!translation.empty() && mToLang != detected_language && LLStringUtil::compareInsensitive(translation, mMsg))
mMsg += " (" + translation + ')';
mPanel->addHistoryLine(mMsg, mColor, mLog, mSource, mName, false, true, mIRC);
}
void handleFailure(int status, const std::string& err_msg)
{
llwarns << "Translation failed for mesg " << mMsg << " toLang " << mToLang << " fromLang " << mFromLang << llendl;
std::string msg = LLTrans::getString("TranslationFailed", LLSD().with("[REASON]", err_msg));
LLStringUtil::replaceString(msg, "\n", " "); // we want one-line error messages
mPanel->addHistoryLine(mMsg + " (" + msg + ')', mColor, mLog, mSource, mName, false, true, mIRC);
}
/*virtual*/ char const* getName() const { return "IMTranslationReceiver"; }
private:
LLFloaterIMPanel* mPanel;
std::string mMsg;
const LLColor4 mColor;
const bool mLog;
const LLUUID mSource;
const std::string mName;
const bool mIRC;
};
void LLFloaterIMPanel::addHistoryLine(const std::string &utf8msg, LLColor4 incolor, bool log_to_file, const LLUUID& source, const std::string& name)
{
bool is_agent(gAgentID == source), from_user(source.notNull());
bool is_agent(gAgentID == source), from_user(name != SYSTEM_FROM && source.notNull());
// IRC style text starts with a colon here; empty names and system messages aren't irc style.
bool is_irc = from_user && utf8msg[0] != ':';
// Now we're adding the actual line of text, so erase the
// "Foo is typing..." text segment, and the optional timestamp
// if it was present. JC
removeTypingIndicator(NULL);
std::string show_name = name;
if (from_user)
{
LLAvatarNameCache::getNSName(source, show_name);
if (mTranslate && !is_agent)
{
const std::string from_lang = ""; // leave empty to trigger autodetect
const std::string to_lang = LLTranslate::getTranslateLanguage();
LLTranslate::TranslationReceiverPtr result = IMTranslationReceiver::build(from_lang, to_lang, this, utf8msg, incolor, log_to_file, source, show_name, is_irc);
LLTranslate::translateMessage(result, from_lang, to_lang, utf8msg);
return;
}
}
addHistoryLine(utf8msg, incolor, log_to_file, source, show_name, is_agent, from_user, is_irc);
}
void LLFloaterIMPanel::addHistoryLine(const std::string& utf8msg, LLColor4 incolor, bool log_to_file, const LLUUID& source, const std::string& name, bool is_agent, bool from_user, bool is_irc)
{
if (!is_agent)
{
static const LLCachedControl<bool> mKeywordsChangeColor(gSavedPerAccountSettings, "KeywordsChangeColor", false);
@@ -729,14 +803,8 @@ void LLFloaterIMPanel::addHistoryLine(const std::string &utf8msg, LLColor4 incol
if (invisible || (!host && focused))
++mNumUnreadMessages;
}
}
// Now we're adding the actual line of text, so erase the
// "Foo is typing..." text segment, and the optional timestamp
// if it was present. JC
removeTypingIndicator(NULL);
// Actually add the line
bool prepend_newline = true;
if (gSavedSettings.getBOOL("IMShowTimestamps"))
@@ -745,27 +813,21 @@ void LLFloaterIMPanel::addHistoryLine(const std::string &utf8msg, LLColor4 incol
prepend_newline = false;
}
std::string show_name = name;
bool is_irc = false;
if (is_irc) is_irc = gSavedSettings.getBOOL("LiruItalicizeActions");
// 'name' is a sender name that we want to hotlink so that clicking on it opens a profile.
if (!name.empty()) // If name exists, then add it to the front of the message.
{
// Don't hotlink any messages from the system (e.g. "Second Life:"), so just add those in plain text.
if (name == SYSTEM_FROM)
if (!from_user)
{
mHistoryEditor->appendColoredText(name,false,prepend_newline,incolor);
}
else
{
// IRC style text starts with a colon here; empty names and system messages aren't irc style.
static const LLCachedControl<bool> italicize("LiruItalicizeActions");
is_irc = italicize && utf8msg[0] != ':';
if (from_user)
LLAvatarNameCache::getNSName(source, show_name);
// Convert the name to a hotlink and add to message.
LLStyleSP source_style = LLStyleMap::instance().lookupAgent(source);
source_style->mItalic = is_irc;
mHistoryEditor->appendStyledText(show_name,false,prepend_newline,source_style);
mHistoryEditor->appendStyledText(name,false,prepend_newline,source_style);
}
prepend_newline = false;
}
@@ -779,21 +841,10 @@ void LLFloaterIMPanel::addHistoryLine(const std::string &utf8msg, LLColor4 incol
mHistoryEditor->appendStyledText(utf8msg, false, prepend_newline, style);
}
if (log_to_file
&& gSavedPerAccountSettings.getBOOL("LogInstantMessages") )
if (log_to_file && gSavedPerAccountSettings.getBOOL("LogInstantMessages"))
{
std::string histstr;
if (gSavedPerAccountSettings.getBOOL("IMLogTimestamp"))
histstr = LLLogChat::timestamp(gSavedPerAccountSettings.getBOOL("LogTimestampDate")) + show_name + utf8msg;
else
histstr = show_name + utf8msg;
// [Ansariel: Display name support]
// Floater title contains display name -> bad idea to use that as filename
// mLogLabel, however, is the old legacy name
//LLLogChat::saveHistory(getTitle(),histstr);
LLLogChat::saveHistory(mLogLabel, histstr);
// [/Ansariel: Display name support]
const std::string histstr(name + utf8msg);
LLLogChat::saveHistory(mLogLabel, gSavedPerAccountSettings.getBOOL("IMLogTimestamp") ? LLLogChat::timestamp(gSavedPerAccountSettings.getBOOL("LogTimestampDate")) + histstr : histstr);
}
if (from_user)
@@ -951,6 +1002,8 @@ void LLFloaterIMPanel::removeDynamics(LLComboBox* flyout)
flyout->remove(mRPMode ? getString("rp mode on") : getString("rp mode off"));
flyout->remove(LLAvatarActions::isFriend(mOtherParticipantUUID) ? getString("remove friend") : getString("add friend"));
flyout->remove(LLAvatarActions::isBlocked(mOtherParticipantUUID) ? getString("unmute") : getString("mute"));
if (mSessionType == P2P_SESSION)
flyout->remove(mTranslate ? getString("translate on") : getString("translate off"));
}
void LLFloaterIMPanel::addDynamics(LLComboBox* flyout)
@@ -959,6 +1012,14 @@ void LLFloaterIMPanel::addDynamics(LLComboBox* flyout)
flyout->add(mRPMode ? getString("rp mode on") : getString("rp mode off"), 7);
flyout->add(LLAvatarActions::isFriend(mOtherParticipantUUID) ? getString("remove friend") : getString("add friend"), 8);
flyout->add(LLAvatarActions::isBlocked(mOtherParticipantUUID) ? getString("unmute") : getString("mute"), 9);
if (mSessionType == P2P_SESSION && LLTranslate::isTranslationConfigured())
flyout->add(mTranslate ? getString("translate on") : getString("translate off"), 10);
}
void LLFloaterIMPanel::rebuildDynamics()
{
if (LLComboBox* flyout = findChild<LLComboBox>("instant_message_flyout"))
rebuildDynamics(flyout);
}
void copy_profile_uri(const LLUUID& id, bool group = false);
@@ -988,6 +1049,7 @@ void LLFloaterIMPanel::onFlyoutCommit(LLComboBox* flyout, const LLSD& value)
else if (option == 7) mRPMode = !mRPMode;
else if (option == 8) LLAvatarActions::isFriend(mOtherParticipantUUID) ? LLAvatarActions::removeFriendDialog(mOtherParticipantUUID) : LLAvatarActions::requestFriendshipDialog(mOtherParticipantUUID);
else if (option == 9) LLAvatarActions::toggleBlock(mOtherParticipantUUID);
else if (option == 10) mTranslate = !mTranslate;
// Last add them back
addDynamics(flyout);

View File

@@ -84,6 +84,7 @@ public:
bool log_to_file = true,
const LLUUID& source = LLUUID::null,
const std::string& name = LLStringUtil::null);
void addHistoryLine(const std::string& utf8msg, LLColor4 incolor, bool log_to_file, const LLUUID& source, const std::string& name, bool is_agent, bool from_user, bool is_irc);
void setInputFocus(bool b);
@@ -137,6 +138,8 @@ public:
static bool onConfirmForceCloseError(const LLSD& notification, const LLSD& response);
void rebuildDynamics();
// LLIMModel Functionality
bool getSessionInitialized() const { return mSessionInitialized; }
bool mStartCallOnInitialize;
@@ -226,6 +229,7 @@ private:
bool mDing; // Whether or not to play a ding on new messages
bool mRPMode;
bool mTranslate;
bool mTextIMPossible;
bool mCallBackEnabled;

View File

@@ -202,14 +202,18 @@ void LLPanelPermissions::disableAll()
getChildView("button set group")->setEnabled(FALSE);
getChildView("button open group")->setEnabled(FALSE);
getChild<LLUICtrl>("Object Name")->setValue(LLStringUtil::null);
getChildView("Object Name")->setEnabled(FALSE);
LLLineEditor* ed = getChild<LLLineEditor>("Object Name");
ed->setValue(LLStringUtil::null);
ed->setEnabled(FALSE);
ed->setLabel(LLStringUtil::null);
getChildView("Name:")->setEnabled(FALSE);
//getChild<LLUICtrl>("Group Name")->setValue(LLStringUtil::null);
//getChildView("Group Name")->setEnabled(FALSE);
getChildView("Description:")->setEnabled(FALSE);
getChild<LLUICtrl>("Object Description")->setValue(LLStringUtil::null);
getChildView("Object Description")->setEnabled(FALSE);
ed = getChild<LLLineEditor>("Object Description");
ed->setEnabled(FALSE);
ed->setValue(LLStringUtil::null);
ed->setLabel(LLStringUtil::null);
getChildView("Permissions:")->setEnabled(FALSE);
@@ -510,7 +514,7 @@ void LLPanelPermissions::refresh()
{
if(keyboard_focus_view != LineEditorObjectName)
{
getChild<LLUICtrl>("Object Name")->setValue(nodep->mName);
LineEditorObjectName->setValue(nodep->mName);
}
if(LineEditorObjectDesc)
@@ -523,25 +527,26 @@ void LLPanelPermissions::refresh()
}
else
{
getChild<LLUICtrl>("Object Name")->setValue(LLStringUtil::null);
LineEditorObjectName->setText(LLStringUtil::null);
LineEditorObjectDesc->setText(LLStringUtil::null);
}
// figure out the contents of the name, description, & category
BOOL edit_name_desc = FALSE;
if(is_one_object && objectp->permModify() && !objectp->isPermanentEnforced())
// Singu Note: It was requested that the user be able to bulk change description
{
edit_name_desc = TRUE;
const std::string& str(object_count > 1 ? getString("multiple_objects_selected") : LLStringUtil::null);
LineEditorObjectName->setLabel(str);
LineEditorObjectDesc->setLabel(str);
}
if(edit_name_desc)
if (/*is_one_object &&*/ objectp->permModify() && !objectp->isPermanentEnforced())
{
getChildView("Object Name")->setEnabled(TRUE);
getChildView("Object Description")->setEnabled(TRUE);
LineEditorObjectName->setEnabled(TRUE);
LineEditorObjectDesc->setEnabled(TRUE);
}
else
{
getChildView("Object Name")->setEnabled(FALSE);
getChildView("Object Description")->setEnabled(FALSE);
LineEditorObjectName->setEnabled(FALSE);
LineEditorObjectDesc->setEnabled(FALSE);
}
S32 total_sale_price = 0;

View File

@@ -0,0 +1,329 @@
/**
* @file llpaneltranslationsettings.cpp
* @brief Machine translation settings for chat
*
* $LicenseInfo:firstyear=2011&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2011, 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 "llpaneltranslationsettings.h"
// Viewer includes
#include "llfloaterchat.h"
#include "llimpanel.h"
#include "llimview.h"
#include "lltranslate.h"
#include "llviewercontrol.h" // for gSavedSettings
// Linden library includes
#include "llbutton.h"
#include "llcheckboxctrl.h"
#include "llcombobox.h"
#include "lllineeditor.h"
#include "llnotificationsutil.h"
#include "llradiogroup.h"
#include "lltexteditor.h"
#include "lluictrlfactory.h"
class EnteredKeyVerifier : public LLTranslate::KeyVerificationReceiver
{
public:
EnteredKeyVerifier(LLTranslate::EService service, bool alert)
: LLTranslate::KeyVerificationReceiver(service)
, mAlert(alert)
{
}
private:
/*virtual*/ void setVerificationStatus(bool ok)
{
LLPanelTranslationSettings* panel = LLPanelTranslationSettings::getInstance();
if (!panel)
{
llwarns << "The translation settings panel has disappeared!" << llendl;
return;
}
switch (getService())
{
case LLTranslate::SERVICE_BING:
panel->setBingVerified(ok, mAlert);
break;
case LLTranslate::SERVICE_GOOGLE:
panel->setGoogleVerified(ok, mAlert);
break;
}
}
/*virtual*/ const char* getName() const { return "EnteredKeyVerifier"; }
bool mAlert;
};
LLPanelTranslationSettings::LLPanelTranslationSettings()
: mMachineTranslationCB(NULL)
, mLanguageCombo(NULL)
, mTranslationServiceRadioGroup(NULL)
, mBingAPIKeyEditor(NULL)
, mGoogleAPIKeyEditor(NULL)
, mBingVerifyBtn(NULL)
, mGoogleVerifyBtn(NULL)
, mBingKeyVerified(false)
, mGoogleKeyVerified(false)
{
LLUICtrlFactory::getInstance()->buildPanel(this, "panel_translation_settings.xml");
mMachineTranslationCB->setValue(gSavedSettings.getBOOL("TranslateChat"));
mLanguageCombo->setSelectedByValue(gSavedSettings.getString("TranslateLanguage"), TRUE);
mTranslationServiceRadioGroup->setSelectedByValue(gSavedSettings.getString("TranslationService"), TRUE);
std::string bing_key = gSavedSettings.getString("BingTranslateAPIKey");
if (!bing_key.empty())
{
mBingAPIKeyEditor->setText(bing_key);
mBingAPIKeyEditor->setTentative(FALSE);
verifyKey(LLTranslate::SERVICE_BING, bing_key, false);
}
else
{
mBingAPIKeyEditor->setTentative(TRUE);
mBingKeyVerified = FALSE;
}
std::string google_key = gSavedSettings.getString("GoogleTranslateAPIKey");
if (!google_key.empty())
{
mGoogleAPIKeyEditor->setText(google_key);
mGoogleAPIKeyEditor->setTentative(FALSE);
verifyKey(LLTranslate::SERVICE_GOOGLE, google_key, false);
}
else
{
mGoogleAPIKeyEditor->setTentative(TRUE);
mGoogleKeyVerified = FALSE;
}
updateControlsEnabledState();
}
// virtual
BOOL LLPanelTranslationSettings::postBuild()
{
mMachineTranslationCB = getChild<LLCheckBoxCtrl>("translate_chat_checkbox");
mLanguageCombo = getChild<LLComboBox>("translate_language_combo");
mTranslationServiceRadioGroup = getChild<LLRadioGroup>("translation_service_rg");
mBingAPIKeyEditor = getChild<LLLineEditor>("bing_api_key");
mGoogleAPIKeyEditor = getChild<LLLineEditor>("google_api_key");
mBingVerifyBtn = getChild<LLButton>("verify_bing_api_key_btn");
mGoogleVerifyBtn = getChild<LLButton>("verify_google_api_key_btn");
mMachineTranslationCB->setCommitCallback(boost::bind(&LLPanelTranslationSettings::updateControlsEnabledState, this));
mTranslationServiceRadioGroup->setCommitCallback(boost::bind(&LLPanelTranslationSettings::updateControlsEnabledState, this));
mBingVerifyBtn->setClickedCallback(boost::bind(&LLPanelTranslationSettings::onBtnBingVerify, this));
mGoogleVerifyBtn->setClickedCallback(boost::bind(&LLPanelTranslationSettings::onBtnGoogleVerify, this));
mBingAPIKeyEditor->setFocusReceivedCallback(boost::bind(&LLPanelTranslationSettings::onEditorFocused, this, _1));
mBingAPIKeyEditor->setKeystrokeCallback(boost::bind(&LLPanelTranslationSettings::onBingKeyEdited, this, _1));
mGoogleAPIKeyEditor->setFocusReceivedCallback(boost::bind(&LLPanelTranslationSettings::onEditorFocused, this, _1));
mGoogleAPIKeyEditor->setKeystrokeCallback(boost::bind(&LLPanelTranslationSettings::onGoogleKeyEdited, this, _1));
// Now set the links, because v3 has special xml linking and we do not.
LLTextEditor* bing_api_key = getChild<LLTextEditor>("bing_api_key_label");
LLTextEditor* google_api_key = getChild<LLTextEditor>("google_api_key_label");
LLTextEditor* google_links = getChild<LLTextEditor>("google_links_text");
google_api_key->setParseHTML(true);
bing_api_key->setParseHTML(true);
google_links->setParseHTML(true);
LLStyleSP link_style(new LLStyle);
link_style->setColor(gSavedSettings.getColor4("HTMLLinkColor"));
std::string link_text;
std::string link_url;
link_text = " AppId:";
link_url = "https://datamarket.azure.com/dataset/1899a118-d202-492c-aa16-ba21c33c06cb"; //Microsoft changed their policy, no longer link to "http://www.bing.com/developers/createapp.aspx";
link_style->setLinkHREF(link_url);
bing_api_key->appendStyledText(link_text, false, false, link_style);
link_text = " API key:";
link_url = "https://developers.google.com/translate/v2/getting_started#auth";
link_style->setLinkHREF(link_url);
google_api_key->appendStyledText(link_text, false, false, link_style);
link_text = getString("Pricing");
link_url = "https://developers.google.com/translate/v2/pricing";
link_style->setLinkHREF(link_url);
google_links->appendStyledText(link_text, false, false, link_style);
google_links->appendColoredText(std::string(" | "), false, false, gColors.getColor("TextFgReadOnlyColor"));
link_text = getString("Stats");
link_url = "https://code.google.com/apis/console";
link_style->setLinkHREF(link_url);
google_links->appendStyledText(link_text, false, false, link_style);
//center();
return TRUE;
}
void LLPanelTranslationSettings::setBingVerified(bool ok, bool alert)
{
if (alert)
{
showAlert(ok ? "bing_api_key_verified" : "bing_api_key_not_verified");
}
mBingKeyVerified = ok;
updateControlsEnabledState();
}
void LLPanelTranslationSettings::setGoogleVerified(bool ok, bool alert)
{
if (alert)
{
showAlert(ok ? "google_api_key_verified" : "google_api_key_not_verified");
}
mGoogleKeyVerified = ok;
updateControlsEnabledState();
}
std::string LLPanelTranslationSettings::getSelectedService() const
{
return mTranslationServiceRadioGroup->getSelectedValue().asString();
}
std::string LLPanelTranslationSettings::getEnteredBingKey() const
{
return mBingAPIKeyEditor->getTentative() ? LLStringUtil::null : mBingAPIKeyEditor->getText();
}
std::string LLPanelTranslationSettings::getEnteredGoogleKey() const
{
return mGoogleAPIKeyEditor->getTentative() ? LLStringUtil::null : mGoogleAPIKeyEditor->getText();
}
void LLPanelTranslationSettings::showAlert(const std::string& msg_name) const
{
LLSD args;
args["MESSAGE"] = getString(msg_name);
LLNotificationsUtil::add("GenericAlert", args);
}
void LLPanelTranslationSettings::updateControlsEnabledState()
{
// Enable/disable controls based on the checkbox value.
bool on = mMachineTranslationCB->getValue().asBoolean();
std::string service = getSelectedService();
bool bing_selected = service == "bing";
bool google_selected = service == "google";
mTranslationServiceRadioGroup->setEnabled(on);
mLanguageCombo->setEnabled(on);
getChild<LLTextEditor>("bing_api_key_label")->setVisible(bing_selected);
mBingAPIKeyEditor->setVisible(bing_selected);
mBingVerifyBtn->setVisible(bing_selected);
getChild<LLTextEditor>("google_api_key_label")->setVisible(google_selected);
getChild<LLTextEditor>("google_links_text")->setVisible(google_selected);
mGoogleAPIKeyEditor->setVisible(google_selected);
mGoogleVerifyBtn->setVisible(google_selected);
mBingAPIKeyEditor->setEnabled(on);
mGoogleAPIKeyEditor->setEnabled(on);
mBingVerifyBtn->setEnabled(on &&
!mBingKeyVerified && !getEnteredBingKey().empty());
mGoogleVerifyBtn->setEnabled(on &&
!mGoogleKeyVerified && !getEnteredGoogleKey().empty());
}
void LLPanelTranslationSettings::verifyKey(int service, const std::string& key, bool alert)
{
LLTranslate::KeyVerificationReceiverPtr receiver =
new EnteredKeyVerifier((LLTranslate::EService) service, alert);
LLTranslate::verifyKey(receiver, key);
}
void LLPanelTranslationSettings::onEditorFocused(LLFocusableElement* control)
{
LLLineEditor* editor = dynamic_cast<LLLineEditor*>(control);
if (editor && editor->hasTabStop()) // if enabled. getEnabled() doesn't work
{
if (editor->getTentative())
{
editor->setText(LLStringUtil::null);
editor->setTentative(FALSE);
}
}
}
void LLPanelTranslationSettings::onBingKeyEdited(LLLineEditor* caller)
{
if (caller->isDirty())
{
setBingVerified(false, false);
}
}
void LLPanelTranslationSettings::onGoogleKeyEdited(LLLineEditor* caller)
{
if (caller->isDirty())
{
setGoogleVerified(false, false);
}
}
void LLPanelTranslationSettings::onBtnBingVerify()
{
std::string key = getEnteredBingKey();
if (!key.empty())
{
verifyKey(LLTranslate::SERVICE_BING, key);
}
}
void LLPanelTranslationSettings::onBtnGoogleVerify()
{
std::string key = getEnteredGoogleKey();
if (!key.empty())
{
verifyKey(LLTranslate::SERVICE_GOOGLE, key);
}
}
void LLPanelTranslationSettings::apply()
{
gSavedSettings.setBOOL("TranslateChat", mMachineTranslationCB->getValue().asBoolean());
gSavedSettings.setString("TranslateLanguage", mLanguageCombo->getSelectedValue().asString());
gSavedSettings.setString("TranslationService", getSelectedService());
gSavedSettings.setString("BingTranslateAPIKey", getEnteredBingKey());
gSavedSettings.setString("GoogleTranslateAPIKey", getEnteredGoogleKey());
LLFloaterChat::getInstance()->showTranslationCheckbox();
std::set<LLHandle<LLFloater> > floaters(LLIMMgr::instance().getIMFloaterHandles());
for(std::set<LLHandle<LLFloater> >::iterator i = floaters.begin(); i != floaters.end(); ++i)
{
LLFloaterIMPanel& floater = static_cast<LLFloaterIMPanel&>(*i->get());
if (floater.getSessionType() == LLFloaterIMPanel::P2P_SESSION)
floater.rebuildDynamics();
}
}

View File

@@ -0,0 +1,75 @@
/**
* @file llpaneltranslationsettings.h
* @brief Machine translation settings for chat
*
* $LicenseInfo:firstyear=2011&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2011, 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_LLPANELTRANSLATIONSETTINGS_H
#define LL_LLPANELTRANSLATIONSETTINGS_H
#include "llpanel.h"
class LLButton;
class LLCheckBoxCtrl;
class LLComboBox;
class LLLineEditor;
class LLRadioGroup;
class LLPanelTranslationSettings : public LLPanel, public LLSingleton<LLPanelTranslationSettings>
{
public:
LLPanelTranslationSettings();
/*virtual*/ BOOL postBuild();
void apply();
void setBingVerified(bool ok, bool alert);
void setGoogleVerified(bool ok, bool alert);
private:
std::string getSelectedService() const;
std::string getEnteredBingKey() const;
std::string getEnteredGoogleKey() const;
void showAlert(const std::string& msg_name) const;
void updateControlsEnabledState();
void verifyKey(int service, const std::string& key, bool alert = true);
void onEditorFocused(LLFocusableElement* control);
void onBingKeyEdited(LLLineEditor* caller);
void onGoogleKeyEdited(LLLineEditor* caller);
void onBtnBingVerify();
void onBtnGoogleVerify();
LLCheckBoxCtrl* mMachineTranslationCB;
LLComboBox* mLanguageCombo;
LLLineEditor* mBingAPIKeyEditor;
LLLineEditor* mGoogleAPIKeyEditor;
LLRadioGroup* mTranslationServiceRadioGroup;
LLButton* mBingVerifyBtn;
LLButton* mGoogleVerifyBtn;
bool mBingKeyVerified;
bool mGoogleKeyVerified;
};
#endif // LL_LLPANELTRANSLATIONSETTINGS_H

View File

@@ -4290,7 +4290,7 @@ void LLSelectMgr::selectionSetObjectName(const std::string& name)
std::string name_copy(name);
// we only work correctly if 1 object is selected.
if(mSelectedObjects->getRootObjectCount() == 1)
if(mSelectedObjects->getRootObjectCount() /*== 1*/) // Singu Note: It was requested that the user be able to bulk rename
{
sendListToRegions("ObjectName",
packAgentAndSessionID,
@@ -4298,7 +4298,7 @@ void LLSelectMgr::selectionSetObjectName(const std::string& name)
(void*)(&name_copy),
SEND_ONLY_ROOTS);
}
else if(mSelectedObjects->getObjectCount() == 1)
else if(mSelectedObjects->getObjectCount() /*== 1*/)
{
sendListToRegions("ObjectName",
packAgentAndSessionID,
@@ -4313,7 +4313,7 @@ void LLSelectMgr::selectionSetObjectDescription(const std::string& desc)
std::string desc_copy(desc);
// we only work correctly if 1 object is selected.
if(mSelectedObjects->getRootObjectCount() == 1)
if (mSelectedObjects->getRootObjectCount() /*== 1*/) // Singu Note: It was requested that the user be able to bulk change description
{
sendListToRegions("ObjectDescription",
packAgentAndSessionID,
@@ -4321,7 +4321,7 @@ void LLSelectMgr::selectionSetObjectDescription(const std::string& desc)
(void*)(&desc_copy),
SEND_ONLY_ROOTS);
}
else if(mSelectedObjects->getObjectCount() == 1)
else if (mSelectedObjects->getObjectCount() /*== 1*/)
{
sendListToRegions("ObjectDescription",
packAgentAndSessionID,

View File

@@ -1727,7 +1727,6 @@ BOOL LLTextureCtrl::doDrop(LLInventoryItem* item)
// no callback installed, so just set the image ids and carry on.
setImageAssetID( item->getAssetUUID() );
mImageItemID = item->getUUID();
mDirty = true;
return TRUE;
}

View File

@@ -2,136 +2,405 @@
* @file lltranslate.cpp
* @brief Functions for translating text via Google Translate.
*
* $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$
*/
* $LicenseInfo:firstyear=2009&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, 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 "llbufferstream.h"
#include "lltranslate.h"
#include <curl/curl.h>
#include "llbufferstream.h"
#include "lltrans.h"
#include "llui.h"
#include "sgversion.h"
#include "llviewercontrol.h"
#include "llweb.h"
// <edit>
#include "llviewercontrol.h"
// </edit>
#include "sgversion.h"
// These two are concatenated with the language specifiers to form a complete Google Translate URL
const char* LLTranslate::m_GoogleURL = "http://ajax.googleapis.com/ajax/services/language/translate?v=1.0&q=";
const char* LLTranslate::m_GoogleLangSpec = "&langpair=";
float LLTranslate::m_GoogleTimeout = 10;
#include "json/reader.h"
AIHTTPHeaders LLTranslate::m_Header;
// These constants are for the GET header.
const char* LLTranslate::m_AcceptHeader = "Accept";
const char* LLTranslate::m_AcceptType = "text/plain";
const char* LLTranslate::m_AgentHeader = "User-Agent";
const LLStringExplicit GOOGLE_URL_BASE("https://www.googleapis.com/language/translate/v2");
const LLStringExplicit BING_URL_BASE("http://api.microsofttranslator.com/v2/Http.svc/");
// These constants are in the JSON returned from Google
const char* LLTranslate::m_GoogleData = "responseData";
const char* LLTranslate::m_GoogleTranslation = "translatedText";
const char* LLTranslate::m_GoogleLanguage = "detectedSourceLanguage";
//static
void LLTranslate::translateMessage(LLHTTPClient::ResponderPtr &result, const std::string &fromLang, const std::string &toLang, const std::string &mesg)
// virtual
void LLGoogleTranslationHandler::getTranslateURL(
std::string &url,
const std::string &from_lang,
const std::string &to_lang,
const std::string &text) const
{
std::string url;
getTranslateUrl(url, fromLang, toLang, mesg);
//<edit>
std::string user_agent = gCurrentVersion;
//</edit>
if (m_Header.empty())
url = std::string(GOOGLE_URL_BASE + "?key=")
+ getAPIKey() + "&q=" + LLURI::escape(text) + "&target=" + to_lang;
if (!from_lang.empty())
{
m_Header.addHeader(m_AcceptHeader, m_AcceptType);
m_Header.addHeader(m_AgentHeader, user_agent);
}
LLHTTPClient::get(url, result, m_Header, m_GoogleTimeout);
}
//static
void LLTranslate::getTranslateUrl(std::string &translateUrl, const std::string &fromLang, const std::string &toLang, const std::string &mesg)
{
std::string escaped_mesg = LLWeb::curlEscape(mesg);
translateUrl = m_GoogleURL
+ escaped_mesg + m_GoogleLangSpec
+ fromLang // 'from' language; empty string for auto
+ "%7C" // |
+ toLang; // 'to' language
}
//static
void LLTranslate::stringReplaceAll(std::string& context, const std::string& from, const std::string& to)
{
size_t lookHere = 0;
size_t foundHere;
while((foundHere = context.find(from, lookHere))
!= std::string::npos) {
context.replace(foundHere, from.size(), to);
lookHere = foundHere + to.size();
url += "&source=" + from_lang;
}
}
//static
BOOL LLTranslate::parseGoogleTranslate(const std::string result, std::string &translation, std::string &detectedLanguage)
// virtual
void LLGoogleTranslationHandler::getKeyVerificationURL(
std::string& url,
const std::string& key) const
{
url = std::string(GOOGLE_URL_BASE + "/languages?key=")
+ key + "&target=en";
}
// virtual
bool LLGoogleTranslationHandler::parseResponse(
int& status,
const std::string& body,
std::string& translation,
std::string& detected_lang,
std::string& err_msg) const
{
Json::Value root;
Json::Reader reader;
BOOL parsingSuccessful = reader.parse(result, root );
if ( !parsingSuccessful )
if (!reader.parse(body, root))
{
LL_WARNS("JSON") << reader.getFormatedErrorMessages() << LL_ENDL;
return FALSE;
err_msg = reader.getFormatedErrorMessages();
return false;
}
translation = root[m_GoogleData].get(m_GoogleTranslation, "").asString();
detectedLanguage = root[m_GoogleData].get(m_GoogleLanguage, "").asString();
return TRUE;
if (!root.isObject()) // empty response? should not happen
{
return false;
}
if (status != STATUS_OK)
{
// Request failed. Extract error message from the response.
parseErrorResponse(root, status, err_msg);
return false;
}
// Request succeeded, extract translation from the response.
return parseTranslation(root, translation, detected_lang);
}
// virtual
bool LLGoogleTranslationHandler::isConfigured() const
{
return !getAPIKey().empty();
}
// static
void LLGoogleTranslationHandler::parseErrorResponse(
const Json::Value& root,
int& status,
std::string& err_msg)
{
const Json::Value& error = root.get("error", 0);
if (!error.isObject() || !error.isMember("message") || !error.isMember("code"))
{
return;
}
err_msg = error["message"].asString();
status = error["code"].asInt();
}
// static
bool LLGoogleTranslationHandler::parseTranslation(
const Json::Value& root,
std::string& translation,
std::string& detected_lang)
{
// JsonCpp is prone to aborting the program on failed assertions,
// so be super-careful and verify the response format.
const Json::Value& data = root.get("data", 0);
if (!data.isObject() || !data.isMember("translations"))
{
return false;
}
const Json::Value& translations = data["translations"];
if (!translations.isArray() || translations.size() == 0)
{
return false;
}
const Json::Value& first = translations[0U];
if (!first.isObject() || !first.isMember("translatedText"))
{
return false;
}
translation = first["translatedText"].asString();
detected_lang = first.get("detectedSourceLanguage", "").asString();
return true;
}
// static
std::string LLGoogleTranslationHandler::getAPIKey()
{
return gSavedSettings.getString("GoogleTranslateAPIKey");
}
// virtual
void LLBingTranslationHandler::getTranslateURL(
std::string &url,
const std::string &from_lang,
const std::string &to_lang,
const std::string &text) const
{
url = std::string(BING_URL_BASE + "Translate?appId=")
+ getAPIKey() + "&text=" + LLURI::escape(text) + "&to=" + getAPILanguageCode(to_lang);
if (!from_lang.empty())
{
url += "&from=" + getAPILanguageCode(from_lang);
}
}
// virtual
void LLBingTranslationHandler::getKeyVerificationURL(
std::string& url,
const std::string& key) const
{
url = std::string(BING_URL_BASE + "GetLanguagesForTranslate?appId=")
+ key;
}
// virtual
bool LLBingTranslationHandler::parseResponse(
int& status,
const std::string& body,
std::string& translation,
std::string& detected_lang,
std::string& err_msg) const
{
if (status != STATUS_OK)
{
static const std::string MSG_BEGIN_MARKER = "Message: ";
size_t begin = body.find(MSG_BEGIN_MARKER);
if (begin != std::string::npos)
{
begin += MSG_BEGIN_MARKER.size();
}
else
{
begin = 0;
err_msg.clear();
}
size_t end = body.find("</p>", begin);
err_msg = body.substr(begin, end-begin);
LLStringUtil::replaceString(err_msg, "&#xD;", ""); // strip CR
return false;
}
// Sample response: <string xmlns="http://schemas.microsoft.com/2003/10/Serialization/">Hola</string>
size_t begin = body.find(">");
if (begin == std::string::npos || begin >= (body.size() - 1))
{
begin = 0;
}
else
{
++begin;
}
size_t end = body.find("</string>", begin);
detected_lang = ""; // unsupported by this API
translation = body.substr(begin, end-begin);
LLStringUtil::replaceString(translation, "&#xD;", ""); // strip CR
return true;
}
// virtual
bool LLBingTranslationHandler::isConfigured() const
{
return !getAPIKey().empty();
}
// static
std::string LLBingTranslationHandler::getAPIKey()
{
return gSavedSettings.getString("BingTranslateAPIKey");
}
// static
std::string LLBingTranslationHandler::getAPILanguageCode(const std::string& lang)
{
return lang == "zh" ? "zh-CHT" : lang; // treat Chinese as Traditional Chinese
}
LLTranslate::TranslationReceiver::TranslationReceiver(const std::string& from_lang, const std::string& to_lang)
: mFromLang(from_lang)
, mToLang(to_lang)
, mHandler(LLTranslate::getPreferredHandler())
{
}
// virtual
void LLTranslate::TranslationReceiver::completedRaw(
const LLChannelDescriptors& channels,
const LLIOPipe::buffer_ptr_t& buffer)
{
LLBufferStream istr(channels, buffer.get());
std::stringstream strstrm;
strstrm << istr.rdbuf();
const std::string body = strstrm.str();
std::string translation, detected_lang, err_msg;
int status = getStatus();
LL_DEBUGS("Translate") << "HTTP status: " << status << " " << getReason() << LL_ENDL;
LL_DEBUGS("Translate") << "Response body: " << body << LL_ENDL;
if (mHandler.parseResponse(status, body, translation, detected_lang, err_msg))
{
// Fix up the response
LLStringUtil::replaceString(translation, "&lt;", "<");
LLStringUtil::replaceString(translation, "&gt;",">");
LLStringUtil::replaceString(translation, "&quot;","\"");
LLStringUtil::replaceString(translation, "&#39;","'");
LLStringUtil::replaceString(translation, "&amp;","&");
LLStringUtil::replaceString(translation, "&apos;","'");
handleResponse(translation, detected_lang);
}
else
{
if (err_msg.empty())
{
err_msg = LLTrans::getString("TranslationResponseParseError");
}
llwarns << "Translation request failed: " << err_msg << llendl;
handleFailure(status, err_msg);
}
}
LLTranslate::KeyVerificationReceiver::KeyVerificationReceiver(EService service)
: mService(service)
{
}
LLTranslate::EService LLTranslate::KeyVerificationReceiver::getService() const
{
return mService;
}
// virtual
void LLTranslate::KeyVerificationReceiver::completedRaw(
const LLChannelDescriptors& channels,
const LLIOPipe::buffer_ptr_t& buffer)
{
bool ok = (getStatus() == 200);
setVerificationStatus(ok);
}
//static
void LLTranslate::translateMessage(
TranslationReceiverPtr &receiver,
const std::string &from_lang,
const std::string &to_lang,
const std::string &mesg)
{
std::string url;
receiver->mHandler.getTranslateURL(url, from_lang, to_lang, mesg);
LL_DEBUGS("Translate") << "Sending translation request: " << url << LL_ENDL;
sendRequest(url, receiver);
}
// static
void LLTranslate::verifyKey(
KeyVerificationReceiverPtr& receiver,
const std::string& key)
{
std::string url;
const LLTranslationAPIHandler& handler = getHandler(receiver->getService());
handler.getKeyVerificationURL(url, key);
LL_DEBUGS("Translate") << "Sending key verification request: " << url << LL_ENDL;
sendRequest(url, receiver);
}
//static
std::string LLTranslate::getTranslateLanguage()
{
std::string language = "en";
if (LLUI::sConfigGroup)
std::string language = gSavedSettings.getString("TranslateLanguage");
if (language.empty() || language == "default")
{
language = LLUI::sConfigGroup->getString("TranslateLanguage");
if (language.empty() || language == "default")
{
language = LLUI::getLanguage();
}
language = LLUI::getLanguage();
}
language = language.substr(0,2);
return language;
}
// static
bool LLTranslate::isTranslationConfigured()
{
return getPreferredHandler().isConfigured();
}
// static
const LLTranslationAPIHandler& LLTranslate::getPreferredHandler()
{
EService service = SERVICE_BING;
std::string service_str = gSavedSettings.getString("TranslationService");
if (service_str == "google")
{
service = SERVICE_GOOGLE;
}
return getHandler(service);
}
// static
const LLTranslationAPIHandler& LLTranslate::getHandler(EService service)
{
static LLGoogleTranslationHandler google;
static LLBingTranslationHandler bing;
if (service == SERVICE_GOOGLE)
{
return google;
}
return bing;
}
// static
void LLTranslate::sendRequest(const std::string& url, LLHTTPClient::ResponderPtr responder)
{
static LLSD sHeader;
if (!sHeader.size())
{
std::string user_agent = llformat("%s %d.%d.%d (%d)",
gVersionChannel,
gVersionMajor,
gVersionMinor,
gVersionPatch,
gVersionBuild);
sHeader.insert("Accept", "text/plain");
sHeader.insert("User-Agent", user_agent);
}
LLHTTPClient::get(url, sHeader, responder);
}

View File

@@ -2,127 +2,301 @@
* @file lltranslate.h
* @brief Human language translation class and JSON response receiver.
*
* $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$
*/
* $LicenseInfo:firstyear=2009&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, 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_LLTRANSLATE_H
#define LL_LLTRANSLATE_H
#include "llhttpclient.h"
#include "llbufferstream.h"
#include "json/reader.h"
#include "lliopipe.h"
class AIHTTPTimeoutPolicy;
extern AIHTTPTimeoutPolicy translationReceiver_timeout;
class LLTranslate
namespace Json
{
public :
class TranslationReceiver : public LLHTTPClient::ResponderWithResult
{
protected:
TranslationReceiver(const std::string &fromLang, const std::string &toLang)
: m_fromLang(fromLang),
m_toLang(toLang)
{
}
class Value;
}
virtual void handleResponse(const std::string &translation, const std::string &recognizedLang) {}
virtual void handleFailure() {};
/**
* Handler of an HTTP machine translation service.
*
* Derived classes know the service URL
* and how to parse the translation result.
*/
class LLTranslationAPIHandler
{
public:
/**
* Get URL for translation of the given string.
*
* Sending HTTP GET request to the URL will initiate translation.
*
* @param[out] url Place holder for the result.
* @param from_lang Source language. Leave empty for auto-detection.
* @param to_lang Target language.
* @param text Text to translate.
*/
virtual void getTranslateURL(
std::string &url,
const std::string &from_lang,
const std::string &to_lang,
const std::string &text) const = 0;
public:
~TranslationReceiver()
{
}
/**
* Get URL to verify the given API key.
*
* Sending request to the URL verifies the key.
* Positive HTTP response (code 200) means that the key is valid.
*
* @param[out] url Place holder for the URL.
* @param[in] key Key to verify.
*/
virtual void getKeyVerificationURL(
std::string &url,
const std::string &key) const = 0;
/*virtual*/ void httpFailure(void)
{
LL_WARNS("Translate") << "URL Request error: " << reason << LL_ENDL;
handleFailure();
}
/**
* Parse translation response.
*
* @param[in,out] status HTTP status. May be modified while parsing.
* @param body Response text.
* @param[out] translation Translated text.
* @param[out] detected_lang Detected source language. May be empty.
* @param[out] err_msg Error message (in case of error).
*/
virtual bool parseResponse(
int& status,
const std::string& body,
std::string& translation,
std::string& detected_lang,
std::string& err_msg) const = 0;
/*virtual*/ void completedRaw(
LLChannelDescriptors const& channels,
LLIOPipe::buffer_ptr_t const& buffer)
{
LLBufferStream istr(channels, buffer.get());
/**
* @return if the handler is configured to function properly
*/
virtual bool isConfigured() const = 0;
std::stringstream strstrm;
strstrm << istr.rdbuf();
const std::string result = strstrm.str();
virtual ~LLTranslationAPIHandler() {}
std::string translation;
std::string detectedLanguage;
protected:
static const int STATUS_OK = 200;
};
if (!parseGoogleTranslate(result, translation, detectedLanguage))
{
handleFailure();
return;
}
/// Google Translate v2 API handler.
class LLGoogleTranslationHandler : public LLTranslationAPIHandler
{
LOG_CLASS(LLGoogleTranslationHandler);
// Fix up the response
stringReplaceAll( translation, "&lt;","<");
stringReplaceAll( translation, "&gt;",">");
stringReplaceAll( translation, "&quot;","\"");
stringReplaceAll( translation, "&#39;","'");
stringReplaceAll( translation, "&amp;","&");
stringReplaceAll( translation, "&apos;","'");
handleResponse(translation, detectedLanguage);
}
/*virtual*/ AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return translationReceiver_timeout; }
protected:
const std::string m_toLang;
const std::string m_fromLang;
};
static void translateMessage(LLHTTPClient::ResponderPtr &result, const std::string &fromLang, const std::string &toLang, const std::string &mesg);
static float m_GoogleTimeout;
static std::string getTranslateLanguage();
public:
/*virtual*/ void getTranslateURL(
std::string &url,
const std::string &from_lang,
const std::string &to_lang,
const std::string &text) const;
/*virtual*/ void getKeyVerificationURL(
std::string &url,
const std::string &key) const;
/*virtual*/ bool parseResponse(
int& status,
const std::string& body,
std::string& translation,
std::string& detected_lang,
std::string& err_msg) const;
/*virtual*/ bool isConfigured() const;
private:
static void getTranslateUrl(std::string &translateUrl, const std::string &fromLang, const std::string &toLang, const std::string &text);
static void stringReplaceAll(std::string& context, const std::string& from, const std::string& to);
static BOOL parseGoogleTranslate(const std::string result, std::string &translation, std::string &detectedLanguage);
static void parseErrorResponse(
const Json::Value& root,
int& status,
std::string& err_msg);
static bool parseTranslation(
const Json::Value& root,
std::string& translation,
std::string& detected_lang);
static std::string getAPIKey();
};
static AIHTTPHeaders m_Header;
static const char* m_GoogleURL;
static const char* m_GoogleLangSpec;
static const char* m_AcceptHeader;
static const char* m_AcceptType;
static const char* m_AgentHeader;
static const char* m_UserAgent;
/// Microsoft Translator v2 API handler.
class LLBingTranslationHandler : public LLTranslationAPIHandler
{
LOG_CLASS(LLBingTranslationHandler);
static const char* m_GoogleData;
static const char* m_GoogleTranslation;
static const char* m_GoogleLanguage;
public:
/*virtual*/ void getTranslateURL(
std::string &url,
const std::string &from_lang,
const std::string &to_lang,
const std::string &text) const;
/*virtual*/ void getKeyVerificationURL(
std::string &url,
const std::string &key) const;
/*virtual*/ bool parseResponse(
int& status,
const std::string& body,
std::string& translation,
std::string& detected_lang,
std::string& err_msg) const;
/*virtual*/ bool isConfigured() const;
private:
static std::string getAPIKey();
static std::string getAPILanguageCode(const std::string& lang);
};
/**
* Entry point for machine translation services.
*
* Basically, to translate a string, we need to know the URL
* of a translation service, have a valid API for the service
* and be given the target language.
*
* Callers specify the string to translate and the target language,
* LLTranslate takes care of the rest.
*
* API keys for translation are taken from saved settings.
*/
class LLTranslate
{
LOG_CLASS(LLTranslate);
public :
typedef enum e_service {
SERVICE_BING,
SERVICE_GOOGLE,
} EService;
/**
* Subclasses are supposed to handle translation results (e.g. show them in chat)
*/
class TranslationReceiver: public LLHTTPClient::ResponderWithCompleted
{
public:
/**
* Using mHandler, parse incoming response.
*
* Calls either handleResponse() or handleFailure()
* depending on the HTTP status code and parsing success.
*
* @see handleResponse()
* @see handleFailure()
* @see mHandler
*/
/*virtual*/ void completedRaw(
const LLChannelDescriptors& channels,
const LLIOPipe::buffer_ptr_t& buffer);
protected:
friend class LLTranslate;
/// Remember source and target languages for subclasses to be able to filter inappropriate results.
TranslationReceiver(const std::string& from_lang, const std::string& to_lang);
virtual void result(LLSD const& content) {};
/// Override point to handle successful translation.
virtual void handleResponse(const std::string &translation, const std::string &recognized_lang) = 0;
/// Override point to handle unsuccessful translation.
virtual void handleFailure(int status, const std::string& err_msg) = 0;
std::string mFromLang;
std::string mToLang;
const LLTranslationAPIHandler& mHandler;
};
/**
* Subclasses are supposed to handle API key verification result.
*/
class KeyVerificationReceiver: public LLHTTPClient::ResponderWithCompleted
{
public:
EService getService() const;
protected:
virtual void result(LLSD const& content) {};
/**
* Save the translation service the key belongs to.
*
* Subclasses need to know it.
*
* @see getService()
*/
KeyVerificationReceiver(EService service);
/**
* Parse verification response.
*
* Calls setVerificationStatus() with the verification status,
* which is true if HTTP status code is 200.
*
* @see setVerificationStatus()
*/
/*virtual*/ void completedRaw(
const LLChannelDescriptors& channels,
const LLIOPipe::buffer_ptr_t& buffer);
/**
* Override point for subclasses to handle key verification status.
*/
virtual void setVerificationStatus(bool ok) = 0;
EService mService;
};
typedef boost::intrusive_ptr<TranslationReceiver> TranslationReceiverPtr;
typedef boost::intrusive_ptr<KeyVerificationReceiver> KeyVerificationReceiverPtr;
/**
* Translate given text.
*
* @param receiver Object to pass translation result to.
* @param from_lang Source language. Leave empty for auto-detection.
* @param to_lang Target language.
* @param mesg Text to translate.
*/
static void translateMessage(TranslationReceiverPtr &receiver, const std::string &from_lang, const std::string &to_lang, const std::string &mesg);
/**
* Verify given API key of a translation service.
*
* @param receiver Object to pass verification result to.
* @param key Key to verify.
*/
static void verifyKey(KeyVerificationReceiverPtr& receiver, const std::string& key);
/**
* @return translation target language
*/
static std::string getTranslateLanguage();
/**
* @return true if translation is configured properly.
*/
static bool isTranslationConfigured();
private:
static const LLTranslationAPIHandler& getPreferredHandler();
static const LLTranslationAPIHandler& getHandler(EService service);
static void sendRequest(const std::string& url, LLHTTPClient::ResponderPtr responder);
};
#endif

View File

@@ -91,6 +91,7 @@
#include "llimview.h"
#include "llspeakers.h"
#include "lltrans.h"
#include "lltranslate.h"
#include "llviewerfoldertype.h"
#include "llviewergenericmessage.h"
#include "llviewermenu.h"
@@ -3612,52 +3613,55 @@ void process_decline_callingcard(LLMessageSystem* msg, void**)
LLNotificationsUtil::add("CallingCardDeclined");
}
#if 0 // Google translate doesn't work anymore
class ChatTranslationReceiver : public LLTranslate::TranslationReceiver
{
public :
ChatTranslationReceiver(const std::string &fromLang, const std::string &toLang, LLChat *chat,
const BOOL history)
: LLTranslate::TranslationReceiver(fromLang, toLang),
ChatTranslationReceiver(const std::string &from_lang, const std::string &to_lang, const std::string &mesg,
const LLChat &chat, const BOOL history)
: LLTranslate::TranslationReceiver(from_lang, to_lang),
m_chat(chat),
m_history(history)
m_history(history),
m_origMesg(mesg)
{
}
static boost::intrusive_ptr<ChatTranslationReceiver> build(const std::string &fromLang, const std::string &toLang, LLChat *chat, const BOOL history)
static boost::intrusive_ptr<ChatTranslationReceiver> build(const std::string &from_lang, const std::string &to_lang, const std::string &mesg, const LLChat &chat, BOOL history)
{
return boost::intrusive_ptr<ChatTranslationReceiver>(new ChatTranslationReceiver(fromLang, toLang, chat, history));
return boost::intrusive_ptr<ChatTranslationReceiver>(new ChatTranslationReceiver(from_lang, to_lang, mesg, chat, history));
}
protected:
void handleResponse(const std::string &translation, const std::string &detectedLanguage)
{
if (m_toLang != detectedLanguage)
m_chat->mText += " (" + translation + ")";
void handleResponse(const std::string &translation, const std::string &detected_language)
{
// filter out non-interesting responeses
if ( !translation.empty()
&& (mToLang != detected_language)
&& (LLStringUtil::compareInsensitive(translation, m_origMesg) != 0) )
{
m_chat.mText += " (" + translation + ")";
}
add_floater_chat(*m_chat, m_history);
delete m_chat;
add_floater_chat(m_chat, m_history);
}
void handleFailure()
void handleFailure(int status, const std::string& err_msg)
{
LLTranslate::TranslationReceiver::handleFailure();
llwarns << "Translation failed for mesg " << m_origMesg << " toLang " << mToLang << " fromLang " << mFromLang << llendl;
m_chat->mText += " (?)";
std::string msg = LLTrans::getString("TranslationFailed", LLSD().with("[REASON]", err_msg));
LLStringUtil::replaceString(msg, "\n", " "); // we want one-line error messages
m_chat.mText += " (" + msg + ")";
add_floater_chat(*m_chat, m_history);
delete m_chat;
add_floater_chat(m_chat, m_history);
}
/*virtual*/ char const* getName(void) const { return "ChatTranslationReceiver"; }
private:
LLChat *m_chat;
const BOOL m_history;
LLChat m_chat;
std::string m_origMesg;
BOOL m_history;
};
#endif
void add_floater_chat(const LLChat &chat, const BOOL history)
{
@@ -3673,29 +3677,6 @@ void add_floater_chat(const LLChat &chat, const BOOL history)
}
}
#if 0 // Google translate doesn't work anymore
void check_translate_chat(const std::string &mesg, LLChat &chat, const BOOL history)
{
const bool translate = LLUI::sConfigGroup->getBOOL("TranslateChat");
if (translate && chat.mSourceType != CHAT_SOURCE_SYSTEM)
{
// fromLang hardcoded to "" (autodetection) pending implementation of
// SVC-4879
const std::string &fromLang = "";
const std::string &toLang = LLTranslate::getTranslateLanguage();
LLChat *newChat = new LLChat(chat);
LLHTTPClient::ResponderPtr result = ChatTranslationReceiver::build(fromLang, toLang, newChat, history);
LLTranslate::translateMessage(result, fromLang, toLang, mesg);
}
else
{
add_floater_chat(chat, history);
}
}
#endif
// defined in llchatbar.cpp, but not declared in any header
void send_chat_from_viewer(std::string utf8_out_text, EChatType type, S32 channel);
@@ -4263,16 +4244,34 @@ void process_chat_from_simulator(LLMessageSystem *msg, void **user_data)
chat.mPosAgent = chatter->getPositionAgent();
}
// truth table:
// LINDEN MUTED BUSY OWNED_BY_YOU TASK DISPLAY STORE IN HISTORY
// F T * * * No No
// F F T F * No Yes
// * F F * * Yes Yes
// * F * T * Yes Yes
// T * * * F Yes Yes
chat.mMuted = is_muted && !is_linden;
bool only_history = visible_in_chat_bubble || (!is_linden && !is_owned_by_me && is_do_not_disturb);
#if 0 // Google translate doesn't work anymore
if (!chat.mMuted)
{
check_translate_chat(mesg, chat, only_history);
LLSD args;
if (chat.mSourceType != CHAT_SOURCE_SYSTEM && gSavedSettings.getBOOL("TranslateChat"))
{
if (ircstyle)
{
mesg.erase(0, 4);
}
const std::string from_lang = ""; // leave empty to trigger autodetect
const std::string to_lang = LLTranslate::getTranslateLanguage();
LLTranslate::TranslationReceiverPtr result = ChatTranslationReceiver::build(from_lang, to_lang, mesg, chat, only_history);
LLTranslate::translateMessage(result, from_lang, to_lang, mesg);
return;
}
}
#else
add_floater_chat(chat, only_history);
#endif
}
}

View File

@@ -1328,7 +1328,7 @@ void LLViewerRegion::setSimulatorFeatures(const LLSD& sim_features)
std::stringstream str;
LLSDSerialize::toPrettyXML(sim_features, str);
LL_DEBUGS("SimFeatures") << "\n" << str.str() << LL_ENDL;
LL_DEBUGS("SimFeatures") << '\n' << str.str() << LL_ENDL;
mSimulatorFeatures = sim_features;
mFeaturesReceived = true;

View File

@@ -45,7 +45,6 @@
#include "llappviewer.h"
#include "hippogridmanager.h"
#include "aicurleasyrequeststatemachine.h"
#ifdef CWDEBUG
@@ -213,6 +212,7 @@ LLXMLRPCValue XMLRPCResponder::responseValue(void) const
}
#ifdef AI_UNUSED
#include "hippogridmanager.h"
void LLXMLRPCTransaction::Impl::setStatus(Status status,
const std::string& message, const std::string& uri)
{

View File

@@ -14,9 +14,6 @@
<combo_box label="Gesten" name="Gesture">
<combo_item name="Gestures">Gesten</combo_item>
</combo_box>
<check_box label="Stummgeschalteten Text anzeigen" name="show mutes"/>
<!--check_box bottom_delta="-15" enabled="true" follows="left|top" font="SansSerifSmall" height="20" initial_value="false" label="Translate Chat (powered by Google)" name="translate chat" width="100"/-->
<button label="Teleport Historie" name="chat_history_open" tool_tip="Klicken Sie hier zur Anzeige des Gesprächsverlaufs im externen Editor"/>
<button label="&lt; &lt;" label_selected="&gt; &gt;" name="toggle_active_speakers_btn" tool_tip="Klicken Sie hier, um eine Liste der aktiven Teilnehmer an dieser IM-Sitzung anzuzeigen."/>

View File

@@ -8,6 +8,10 @@
<string name="voice_icon">icn_voice-localchat.tga</string>
<string name="IM_logging_string">-- Logging Enabled --</string>
<string name="IM_end_log_string">-- End of Log --</string>
<string name="show muted text" value="Show Muted Text"/>
<string name="hide muted text" value="Hide Muted Text"/>
<string name="translate on" value="Translate (on)"/>
<string name="translate off" value="Translate (off)"/>
<layout_stack border="false" bottom="0" follows="left|top|right|bottom" height="160" left="0" orientation="horizontal" width="430" name="panels">
<layout_panel border="false" bottom="0" height="160" left="0" min_width="275" name="im_contents_panel" width="305">
<layout_stack border="false" bottom="0" default_tab_group="1" follows="all" height="160" left="0" orientation="vertical" name="im_contents_stack" width="305">
@@ -15,12 +19,10 @@
<combo_box follows="left|top" height="18" label="Gestures" left="6" name="Gesture" width="120">
<combo_item name="Gestures">Gestures</combo_item>
</combo_box>
<check_box bottom_delta="-2" enabled="true" follows="left|top" font="SansSerifSmall" height="20" initial_value="false" label="Show Muted Text" left_delta="124" name="show mutes" width="116"/>
<!--check_box bottom_delta="-15" enabled="true" follows="left|top" font="SansSerifSmall" height="20" initial_value="false" label="Translate Chat (powered by Google)" name="translate chat" width="100" control_name="TranslateChat"/-->
<button bottom_delta="2" left_delta="120" follows="left|top" font="SansSerifSmall" height="20" width="100" label="Open History" name="chat_history_open" tool_tip="Click here to open chat history in external editor."/>
<flyout_button bottom="-23" height="20" left_delta="124" label="Open History" left="5" name="history_combo" font="SansSerifSmall" width="120" list_position="below"/>
<button bottom_delta="0" follows="right|top" height="20" label="&lt; &lt;" label_selected="&gt; &gt;" toggle="true" left="272" name="toggle_active_speakers_btn" right="305" tool_tip="Click here to show a list of active participants in this IM session." width="80"/>
<text_editor type="string" length="1" bg_readonly_color="ChatHistoryBgColor" bg_writeable_color="ChatHistoryBgColor" bottom="0" enabled="false" follows="left|top|right|bottom" font="SansSerif" height="107" left="5" max_length="2147483647" name="Chat History Editor" text_color="ChatHistoryTextColor" track_bottom="true" text_readonly_color="ChatHistoryTextColor" width="300" word_wrap="true"/>
<text_editor type="string" length="1" bg_readonly_color="ChatHistoryBgColor" bg_writeable_color="ChatHistoryBgColor" bottom="0" enabled="false" follows="left|top|right|bottom" font="SansSerif" height="107" max_length="2147483647" name="Chat History Editor with mute" text_color="ChatHistoryTextColor" track_bottom="true" text_readonly_color="ChatHistoryTextColor" width="300" word_wrap="true"/>
<text_editor type="string" length="1" bg_readonly_color="ChatHistoryBgColor" bg_writeable_color="ChatHistoryBgColor" bottom="0" enabled="false" follows="left|top|right|bottom" font="SansSerif" height="107" left="5" max_length="2147483647" name="Chat History Editor" text_color="ChatHistoryTextColor" track_bottom="true" text_readonly_color="ChatHistoryTextColor" width="300" word_wrap="true" invisibility_control="SinguShowMutedLocal"/>
<text_editor type="string" length="1" bg_readonly_color="ChatHistoryBgColor" bg_writeable_color="ChatHistoryBgColor" bottom="0" enabled="false" follows="left|top|right|bottom" font="SansSerif" height="107" max_length="2147483647" name="Chat History Editor with mute" text_color="ChatHistoryTextColor" track_bottom="true" text_readonly_color="ChatHistoryTextColor" width="300" word_wrap="true" visibility_control="SinguShowMutedLocal"/>
</layout_panel>
<layout_panel user_resize="false" auto_resize="false" bottom_delta="-25" follows="left|right|bottom" left="5" name="chat_layout_panel" right="-5" tab_group="1" height="25">
<panel bottom="5" follows="left|right|bottom" left="5" name="chat_panel" right="-5" top="25">

View File

@@ -24,6 +24,8 @@
<string name="remove friend" value="Remove Friend"/>
<string name="mute" value="Mute"/>
<string name="unmute" value="Unmute"/>
<string name="translate on" value="Translate (on)"/>
<string name="translate off" value="Translate (off)"/>
<button bottom_delta="0" follows="left|top" height="20" left_delta="81" width="50" name="tp_btn" label="TP"/>
<button bottom_delta="0" follows="left|top" height="20" left_delta="50" width="50" name="pay_btn" label="Pay"/>
<button bottom_delta="0" follows="left|top" height="20" left_delta="50" width="50" name="history_btn" label="Log"/>

View File

@@ -28,6 +28,8 @@
<string name="remove friend" value="Remove Friend"/>
<string name="mute" value="Mute"/>
<string name="unmute" value="Unmute"/>
<string name="translate on" value="Translate (on)"/>
<string name="translate off" value="Translate (off)"/>
<button bottom="-20" follows="right|top" height="20" image_overlay="icn_voice-call-start.tga" image_overlay_alignment="left" label="Call" left_delta="81" name="start_call_btn" width="60"/>
<button bottom="-20" follows="right|top" height="20" image_overlay="icn_voice-call-end.tga" image_overlay_alignment="left" scale_image="true" label="End" name="end_call_btn" width="24"/>
<panel mouse_opaque="false" border="false" bottom="-20" follows="right|top" height="20" left_delta="16" name="speaker_controls" width="60">

View File

@@ -443,6 +443,7 @@
follows="left|top|right" font="SansSerifSmall" height="16" left="88"
max_length="127" mouse_opaque="true" name="Object Description"
select_all_on_focus_received="true" width="172" />
<string name="multiple_objects_selected" value="Multiple (bulk change mode)"/>
<text bg_visible="false" border_drop_shadow_visible="false" border_visible="false"
bottom="-66" drop_shadow_visible="true" follows="left|top"
font="SansSerifSmall" h_pad="0" halign="left" height="16" left="10"

View File

@@ -164,37 +164,37 @@ The following wildcards are available to enhance your autoresponses: #n for user
</panel>
<panel border="true" bottom="-580" height="525" label="Text Options" left="1" name="TextOptions" width="418">
<check_box bottom="-25" left="12" height="16" label="Show misspelled words in red" name="SpellDisplay" control_name="SpellDisplay"/>
<text bottom_delta="-24" follows="left|top" height="16" name="EmSpell_txt1">Current language (dictionary):</text>
<combo_box bottom_delta="-20" follows="left|top" height="20" name="SpellBase" width="250" control_name="SpellBase"/>
<text bottom_delta="-24" follows="left|top" height="20" name="EmSpell_txt3">Downloaded languages (dictionaries):</text>
<combo_box bottom_delta="-20" follows="left|top" height="20" name="EmSpell_Avail" width="250" control_name="EmSpell_Avail"/>
<button bottom_delta="0" left_delta="255" follows="left|top" height="20" label="Install" name="EmSpell_Add" tool_tip="" width="80"/>
<button bottom_delta="-22" left="12" follows="top" height="20" label="Download More..." name="EmSpell_GetMore" tool_tip="Get more dictionaries availabe online" width="250"/>
<text bottom_delta="-24" follows="left|top" height="20" name="EmSpell_txt2">Additional custom languages (dictionaries):</text>
<combo_box bottom_delta="-20" follows="left|top" height="20" name="EmSpell_Installed" width="250" control_name="EmSpell_Installed" tool_tip=""/>
<button bottom_delta="0" left_delta="255" follows="left|top" height="20" label="Remove" name="EmSpell_Remove" tool_tip="" width="80"/>
<button bottom_delta="-20" left="12" follows="top" height="20" label="Edit Custom dictionary" name="EmSpell_EditCustom" width="250"/>
<text bottom_delta="-24" follows="left|top" height="20" name="EmSpell_txt4">
To use spellcheck, right-click a misspelled word
(red or otherwise) and select its replacement
</text>
<button bottom_delta="-26" left="12" follows="top" height="20" width="190" label="Autoreplace Preferences" name="autoreplace"/>
<button bottom_delta="-26" left="12" follows="top" height="20" width="250" label="Autoreplace Preferences" name="autoreplace"/>
<view_border bevel_style="none" border_thickness="1" bottom_delta="-5" follows="top" height="0" left="5" name="CmdDivisor" width="376"/>
<text bottom_delta="-24" left="12" follows="left|top" height="16" font="SansSerif" name="Spell_txt">Dictionaries:</text>
<check_box bottom_delta="0" left_delta="110" follows="left|top" height="16" label="Show misspelled words in red" name="SpellDisplay" control_name="SpellDisplay"/>
<text bottom_delta="-24" left="12" follows="left|top" height="20" name="Spell_txt1">Current:</text>
<combo_box bottom_delta="5" left_delta="85" follows="left|top" height="20" name="SpellBase" width="190" control_name="SpellBase"/>
<text bottom_delta="-24" left="12" follows="left|top" height="20" name="Spell_txt2">Downloaded:</text>
<combo_box bottom_delta="5" left_delta="85" follows="left|top" height="20" name="EmSpell_Avail" width="190" control_name="EmSpell_Avail"/>
<button bottom_delta="0" left_delta="195" follows="left|top" height="20" label="Install" name="EmSpell_Add" width="80"/>
<button bottom_delta="0" left_delta="80" follows="top" height="20" label="Get More..." name="EmSpell_GetMore" tool_tip="Get more dictionaries availabe online" width="90"/>
<text bottom_delta="-24" left="12" follows="left|top" height="20" name="Spell_txt3">Custom:</text>
<combo_box bottom_delta="5" left_delta="85" follows="left|top" height="20" name="EmSpell_Installed" width="190" control_name="EmSpell_Installed" tool_tip=""/>
<button bottom_delta="0" left_delta="195" follows="left|top" height="20" label="Remove" name="EmSpell_Remove" width="80"/>
<button bottom_delta="0" left_delta="80" follows="top" height="20" label="Edit..." name="EmSpell_EditCustom" width="90"/>
<text bottom_delta="-24" left="12" follows="left|top" height="20" name="EmSpell_txt4" width="500">
To use spellcheck, right-click a misspelled word (red or otherwise) and select its replacement
</text>
<view_border bevel_style="none" border_thickness="1" bottom_delta="-5" follows="top" height="0" left="5" name="TextDivisor" width="480"/>
<panel border="true" left="1" bottom_delta="-90" height="100" width="500" filename="panel_translation_settings.xml" label="Translation" name="Translation Panel"/>
<view_border bevel_style="none" border_thickness="1" bottom_delta="-10" follows="top" height="0" left="5" name="TransDivisor" width="480"/>
<check_box bottom_delta="-24" follows="left|top" font="SansSerifSmall" height="16"
label="Highlight messages if any of them contain the terms" name="KeywordsOn" width="270"/>
<text bottom_delta="-20" follows="top" height="20" left="12" name="keyword_txt1">(separated by commas)</text>
<line_editor bevel_style="in" border_style="line" border_thickness="1" bottom_delta="-20" follows="top" height="20" left_delta="5" max_length="500" name="KeywordsList" width="300"/>
label="Highlight messages if any of them contain the terms (separated by commas)" name="KeywordsOn" width="300"/>
<line_editor bevel_style="in" border_style="line" border_thickness="1" bottom_delta="-20" follows="top" height="20" left_delta="5" max_length="500" name="KeywordsList" width="390"/>
<text bottom_delta="-24" follows="top" height="20" left_delta="0" name="EmKeyw">Is found within:</text>
<check_box bottom_delta="3" follows="top" height="16" left_delta="80" label="Local Chat Floater" name="KeywordsInChat"/>
<check_box bottom_delta="0" left_delta="120" follows="left|top" height="16" label="Instant Message Floater" name="KeywordsInIM"/>
<check_box bottom_delta="-24" follows="top" height="16" label="Highlight the message in this color:" left_delta="-195" name="KeywordsChangeColor"/>
<check_box bottom_delta="-20" follows="top" height="16" label="Highlight the message in this color:" left_delta="-200" name="KeywordsChangeColor"/>
<color_swatch border_color="0.45098, 0.517647, 0.607843, 1" bottom_delta="-16" can_apply_immediately="true" color="1, 1, 1, 1" follows="left|top" height="35" left_delta="210" name="KeywordsColor" tool_tip="Click to open Color Picker" width="50"/>
<check_box bottom_delta="-10" follows="top" height="16" left_delta="-210" label="Play this sound alert: (UUID)" name="KeywordsPlaySound"/>
<line_editor bottom_delta="-20" follows="left|top" bevel_style="in" border_style="line" border_thickness="1" height="20" left_delta="-5" max_length="36" name="KeywordsSound" width="300"/>
<check_box bottom_delta="-10" follows="top" height="16" left_delta="-210" label="Play this sound alert (UUID):" name="KeywordsPlaySound"/>
<line_editor bottom_delta="0" follows="left|top" bevel_style="in" border_style="line" border_thickness="1" height="20" left_delta="180" max_length="36" name="KeywordsSound" width="210"/>
</panel>
</tab_container>
</panel>

View File

@@ -0,0 +1,51 @@
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<panel height="310" name="panel_translation_settings" title="Translation" width="485">
<string name="bing_api_key_not_verified">Bing appID not verified. Please try again.</string>
<string name="google_api_key_not_verified">Google API key not verified. Please try again.</string>
<string name="bing_api_key_verified">Bing appID verified.</string>
<string name="google_api_key_verified">Google API key verified.</string>
<check_box label="Enable machine translation while chatting" left="5" name="translate_chat_checkbox" control_name="TranslateChat" bottom="-30" width="20"/>
<text follows="left|top" left="12" bottom_delta="-20" name="translate_language_label">Translate chat into: </text>
<combo_box allow_text_entry="true" follows="left|top" height="20" max_chars="135" name="translate_language_combo" control_name="TranslateLanguage" bottom_delta="-6" left_delta="100" width="190">
<combo_item name="System Default Language" value="default">System Default</combo_item>
<combo_item name="English" value="en">English</combo_item>
<!-- After "System Default" and "English", please keep the rest of these combo_items in alphabetical order by the first character in the string. -->
<combo_item name="Danish" value="da">Dansk (Danish)</combo_item>
<combo_item name="German" value="de">Deutsch (German)</combo_item>
<combo_item name="Spanish" value="es">Español (Spanish)</combo_item>
<combo_item name="French" value="fr">Français (French)</combo_item>
<combo_item name="Italian" value="it">Italiano (Italian)</combo_item>
<combo_item name="Hungarian" value="hu">Magyar (Hungarian)</combo_item>
<combo_item name="Dutch" value="nl">Nederlands (Dutch)</combo_item>
<combo_item name="Polish" value="pl">Polski (Polish)</combo_item>
<combo_item name="Portugese" value="pt">Português (Portuguese)</combo_item>
<combo_item name="Russian" value="ru">Русский (Russian)</combo_item>
<combo_item name="Turkish" value="tr">Türkçe (Turkish)</combo_item>
<combo_item name="Ukrainian" value="uk">Українська (Ukrainian)</combo_item>
<combo_item name="Chinese" value="zh">中文 (正體) (Chinese)</combo_item>
<combo_item name="Japanese" value="ja">日本語 (Japanese)</combo_item>
<combo_item name="Korean" value="ko">한국어 (Korean)</combo_item>
</combo_box>
<text follows="top|left|right" left="12" bottom_delta="-18" name="tip">Choose translation service:</text>
<radio_group draw_border="false" follows="top|left" bottom_delta="-7" left_delta="160" height="20" width="300" name="translation_service_rg" control_name="TranslationService">
<radio_item value="bing" name="bing" bottom="0" left="0" height="20">Bing Translator</radio_item>
<radio_item value="google" name="google" bottom="0" left_delta="60">Google Translate</radio_item>
</radio_group>
<text_editor enabled="false" font="SansSerifSmall" hide_scrollbar="true" hide_border="true" bg_readonly_color="0 0 0 0" follows="top|right" height="20" width="109" bottom_delta="-24" left="5" name="bing_api_key_label">
Bing
</text_editor>
<line_editor label="Enter Bing AppID and click &quot;Verify&quot;" follows="top|left" height="20" bottom_delta="0" left_delta="105" max_length_chars="50" top_delta="-4" name="bing_api_key" control_name="BingTranslateAPIKey" width="210"/>
<button follows="left|top" height="20" label="Verify" bottom_delta="0" left_delta="215" name="verify_bing_api_key_btn" width="80"/>
<text_editor enabled="false" font="SansSerifSmall" hide_scrollbar="true" hide_border="true" bg_readonly_color="0 0 0 0" follows="top|right" height="20" bottom_delta="0" width="109" left="5" name="google_api_key_label">
Google
</text_editor>
<line_editor label="Enter Google API key and click &quot;Verify&quot;" follows="top|left" height="20" bottom_delta="0" left_delta="105" max_length_chars="50" top_delta="-4" name="google_api_key" control_name="GoogleTranslateAPIKey" width="210"/>
<button follows="left|top" height="20" label="Verify" bottom_delta="0" left_delta="215" name="verify_google_api_key_btn" width="80"/>
<text_editor enabled="false" font="SansSerifSmall" hide_scrollbar="true" hide_border="true" bg_readonly_color="0 0 0 0" follows="top|right" height="20" left_delta="70" name="google_links_text" bottom_delta="0"/>
<string name="Pricing">Pricing</string>
<string name="Stats">Stats</string>
</panel>

View File

@@ -4417,6 +4417,11 @@ Try enclosing path to the editor with double quotes.
<string name="ExternalEditorCommandParseError">Error parsing the external editor command.</string>
<string name="ExternalEditorFailedToRun">External editor failed to run.</string>
<!-- Machine translation of chat messages -->
<string name="TranslationFailed">Translation failed: [REASON]</string>
<string name="TranslationResponseParseError">Error parsing translation response.</string>
<!-- Key names begin -->
<string name="Left">Left</string>
<string name="Right">Right</string>

View File

@@ -27,8 +27,6 @@
Gestos
</combo_item>
</combo_box>
<check_box label="Mostrar Texto Ignorado" name="show mutes"/>
<button label="Abrir Historial" name="chat_history_open" tool_tip="Pulsá aquí para abrir el historial de chat en un editor externo." left_delta="150"/>
<button label="&lt; &lt;" label_selected="&gt; &gt;" name="toggle_active_speakers_btn" tool_tip="Pulsa aqui para ver la lista de los participantes en esta sesión de MI"/>
<text_editor name="Chat History Editor"/>
<text_editor name="Chat History Editor with mute"/>

View File

@@ -11,8 +11,6 @@
<layout_panel name="im_contents_panel">
<layout_stack name="im_contents_stack">
<layout_panel name="history_panel">
<check_box label="Montre le Texte mute" name="show mutes"/>
<button label="Historique" name="chat_history_open" tool_tip="" left_delta="150"/>
<button name="toggle_active_speakers_btn" tool_tip=""/>
</layout_panel>
<layout_panel name="chat_layout_panel">

View File

@@ -28,7 +28,6 @@
Gesture
</combo_item>
</combo_box>
<check_box label="Mostra testo mutato" name="show mutes"/>
<button label="&lt; &lt;" label_selected="&gt; &gt;" name="toggle_active_speakers_btn" tool_tip="Clicca qui per vedere la lista dei partecipanti attivi in questa sessione IM."/>
<panel name="chat_panel">
<string name="gesture_label">

View File

@@ -28,7 +28,6 @@
Gestos
</combo_item>
</combo_box>
<check_box label="Mostrar texto silenciado" name="show mutes"/>
<button label="&lt; &lt;" label_selected="&gt; &gt;" name="toggle_active_speakers_btn" tool_tip="Clique aqui para mostrar uma lista dos participantes ativos desta sessão de mensagem instantânea."/>
<panel name="chat_panel">
<string name="gesture_label">