Upload-to-Flickr
parent
be1566309a
commit
882c80b778
|
|
@ -125,6 +125,10 @@ set(VIEWER ON CACHE BOOL "Build Firestorm viewer.")
|
|||
set(VIEWER_CHANNEL "FirestormPrivate" CACHE STRING "Viewer Channel Name")
|
||||
set(VIEWER_LOGIN_CHANNEL ${VIEWER_CHANNEL} CACHE STRING "Fake login channel for A/B Testing")
|
||||
|
||||
# Flickr API keys.
|
||||
set(FLICKR_API_KEY "ebc94a4d2651c33404b0fb8ee1b78958")
|
||||
set(FLICKR_API_SECRET "73efdfa10ebe7625")
|
||||
|
||||
set(STANDALONE OFF CACHE BOOL "Do not use Linden-supplied prebuilt libraries.")
|
||||
|
||||
if (NOT STANDALONE AND EXISTS ${CMAKE_SOURCE_DIR}/llphysics)
|
||||
|
|
|
|||
|
|
@ -180,6 +180,18 @@ std::string LLURI::escape(const std::string& str)
|
|||
return escape(str, default_allowed, true);
|
||||
}
|
||||
|
||||
//static
|
||||
std::string LLURI::escapeQueryValue(const std::string& s)
|
||||
{
|
||||
return ::escapeQueryValue(s);
|
||||
}
|
||||
|
||||
//static
|
||||
std::string LLURI::escapeQueryVariable(const std::string& s)
|
||||
{
|
||||
return ::escapeQueryVariable(s);
|
||||
}
|
||||
|
||||
LLURI::LLURI()
|
||||
{
|
||||
}
|
||||
|
|
@ -595,10 +607,10 @@ std::string LLURI::mapToQueryString(const LLSD& queryMap)
|
|||
{
|
||||
ostr << "&";
|
||||
}
|
||||
ostr << escapeQueryVariable(iter->first);
|
||||
ostr << ::escapeQueryVariable(iter->first);
|
||||
if(iter->second.isDefined())
|
||||
{
|
||||
ostr << "=" << escapeQueryValue(iter->second.asString());
|
||||
ostr << "=" << ::escapeQueryValue(iter->second.asString());
|
||||
}
|
||||
}
|
||||
query_string = ostr.str();
|
||||
|
|
|
|||
|
|
@ -134,6 +134,28 @@ public:
|
|||
*/
|
||||
static std::string escape(const std::string& str);
|
||||
|
||||
/**
|
||||
* @brief The same as escape, but also does not escape:
|
||||
* :@!$'()*+,=
|
||||
*
|
||||
* @see http://www.ietf.org/rfc/rfc1738.txt
|
||||
*
|
||||
* @param str The raw URI to escape.
|
||||
* @return Returns the escaped uri or an empty string.
|
||||
*/
|
||||
static std::string escapeQueryValue(const std::string& str);
|
||||
|
||||
/**
|
||||
* @brief The same as escape, but also does not escape:
|
||||
* :@!$'()*+,
|
||||
*
|
||||
* @see http://www.ietf.org/rfc/rfc1738.txt
|
||||
*
|
||||
* @param str The raw URI to escape.
|
||||
* @return Returns the escaped uri or an empty string.
|
||||
*/
|
||||
static std::string escapeQueryVariable(const std::string& str);
|
||||
|
||||
/**
|
||||
* @brief Escape a string with a specified set of allowed characters.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -77,6 +77,23 @@ BOOL LLXmlTree::parseFile(const std::string &path, BOOL keep_contents)
|
|||
return success;
|
||||
}
|
||||
|
||||
|
||||
BOOL LLXmlTree::parseString(const std::string &string, BOOL keep_contents)
|
||||
{
|
||||
delete mRoot;
|
||||
mRoot = NULL;
|
||||
|
||||
LLXmlTreeParser parser(this);
|
||||
BOOL success = parser.parseString( string, &mRoot, keep_contents );
|
||||
if( !success )
|
||||
{
|
||||
S32 line_number = parser.getCurrentLineNumber();
|
||||
const char* error = parser.getErrorString();
|
||||
llwarns << "LLXmlTree parse failed. Line " << line_number << ": " << error << llendl;
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
void LLXmlTree::dump()
|
||||
{
|
||||
if( mRoot )
|
||||
|
|
@ -517,14 +534,35 @@ BOOL LLXmlTreeParser::parseFile(const std::string &path, LLXmlTreeNode** root, B
|
|||
{
|
||||
llassert( !mRoot );
|
||||
llassert( !mCurrent );
|
||||
|
||||
|
||||
mKeepContents = keep_contents;
|
||||
|
||||
|
||||
BOOL success = LLXmlParser::parseFile(path);
|
||||
|
||||
|
||||
*root = mRoot;
|
||||
mRoot = NULL;
|
||||
|
||||
if( success )
|
||||
{
|
||||
llassert( !mCurrent );
|
||||
}
|
||||
mCurrent = NULL;
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
BOOL LLXmlTreeParser::parseString(const std::string &string, LLXmlTreeNode** root, BOOL keep_contents)
|
||||
{
|
||||
llassert( !mRoot );
|
||||
llassert( !mCurrent );
|
||||
|
||||
mKeepContents = keep_contents;
|
||||
|
||||
BOOL success = LLXmlParser::parse(string.c_str(), string.length(), true);
|
||||
|
||||
*root = mRoot;
|
||||
mRoot = NULL;
|
||||
|
||||
if( success )
|
||||
{
|
||||
llassert( !mCurrent );
|
||||
|
|
|
|||
|
|
@ -56,6 +56,7 @@ public:
|
|||
void cleanup();
|
||||
|
||||
virtual BOOL parseFile(const std::string &path, BOOL keep_contents = TRUE);
|
||||
virtual BOOL parseString(const std::string &string, BOOL keep_contents = TRUE);
|
||||
|
||||
LLXmlTreeNode* getRoot() { return mRoot; }
|
||||
|
||||
|
|
@ -200,6 +201,7 @@ public:
|
|||
virtual ~LLXmlTreeParser();
|
||||
|
||||
BOOL parseFile(const std::string &path, LLXmlTreeNode** root, BOOL keep_contents );
|
||||
BOOL parseString(const std::string &string, LLXmlTreeNode** root, BOOL keep_contents);
|
||||
|
||||
protected:
|
||||
const std::string& tabs();
|
||||
|
|
|
|||
|
|
@ -66,6 +66,7 @@ include_directories(
|
|||
${LSCRIPT_INCLUDE_DIRS}/lscript_compile
|
||||
${LLLOGIN_INCLUDE_DIRS}
|
||||
${UPDATER_INCLUDE_DIRS}
|
||||
${CMAKE_BINARY_DIR}/newview
|
||||
)
|
||||
|
||||
set(viewer_SOURCE_FILES
|
||||
|
|
@ -591,6 +592,9 @@ set(viewer_SOURCE_FILES
|
|||
noise.cpp
|
||||
panel_prefs_firestorm.cpp
|
||||
pipeline.cpp
|
||||
kvflickr.cpp
|
||||
kvfloaterflickrauth.cpp
|
||||
kvfloaterflickrupload.cpp
|
||||
qtoolalign.cpp
|
||||
rlvhandler.cpp
|
||||
rlvhelper.cpp
|
||||
|
|
@ -1155,8 +1159,18 @@ set(viewer_HEADER_FILES
|
|||
streamtitledisplay.h
|
||||
VertexCache.h
|
||||
VorbisFramework.h
|
||||
kvflickr.h
|
||||
kvfloaterflickrauth.h
|
||||
kvfloaterflickrupload.h
|
||||
)
|
||||
|
||||
# Generate the Flickr Keys header
|
||||
configure_file(
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/kvflickrkeys.h.in
|
||||
${CMAKE_CURRENT_BINARY_DIR}/kvflickrkeys.h
|
||||
@ONLY
|
||||
)
|
||||
list(APPEND viewer_HEADER_FILES ${CMAKE_CURRENT_BINARY_DIR}/kvflickrkeys.h)
|
||||
source_group("CMake Rules" FILES ViewerInstall.cmake)
|
||||
|
||||
if (DARWIN)
|
||||
|
|
|
|||
|
|
@ -13425,5 +13425,49 @@ Change of this parameter will affect the layout of buttons in notification toast
|
|||
<key>Value</key>
|
||||
<integer>0</integer>
|
||||
</map>
|
||||
<key>KittyFlickrLastRating</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Last rating for Flickr upload. 1 = safe, 2 = moderate, 3 = restricted</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>S32</string>
|
||||
<key>Value</key>
|
||||
<integer>1</integer>
|
||||
</map>
|
||||
<key>KittyFlickrLastTags</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Last tags used on Flickr upload</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>String</string>
|
||||
<key>Value</key>
|
||||
<string>"Second Life"</string>
|
||||
</map>
|
||||
<key>KittyFlickrShowPosition</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Whether to show the position of a Flickr upload</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>Boolean</string>
|
||||
<key>Value</key>
|
||||
<integer>1</integer>
|
||||
</map>
|
||||
<key>KittyFlickrIncludeSLURL</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>If showing the position of an image, whether an SLurl should be included in the description.</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>Boolean</string>
|
||||
<key>Value</key>
|
||||
<integer>1</integer>
|
||||
</map>
|
||||
</map>
|
||||
</llsd>
|
||||
|
|
|
|||
|
|
@ -196,6 +196,39 @@
|
|||
<!-- End of back compatibility settings -->
|
||||
|
||||
<!-- Firestorm settings -->
|
||||
<key>KittyFlickrToken</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Token used to authenticate with Flickr</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>String</string>
|
||||
<key>Value</key>
|
||||
<string></string>
|
||||
</map>
|
||||
<key>KittyFlickrUsername</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Username associated with Flickr account</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>String</string>
|
||||
<key>Value</key>
|
||||
<string></string>
|
||||
</map>
|
||||
<key>KittyFlickrNSID</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>NSID associated with Flickr account</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>String</string>
|
||||
<key>Value</key>
|
||||
<string></string>
|
||||
</map>
|
||||
<key>DebugLookAt</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,296 @@
|
|||
/**
|
||||
* @file kvflickr.cpp
|
||||
* @brief Basic Flickr library for the client.
|
||||
* @copyright Copyright (c) 2011 Katharine Berry
|
||||
*
|
||||
* 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; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
#include "llviewerprecompiledheaders.h"
|
||||
|
||||
#include "llbufferstream.h"
|
||||
#include "lluri.h"
|
||||
#include "llmd5.h"
|
||||
#include "llhttpclient.h"
|
||||
#include "llxmltree.h"
|
||||
#include "jsoncpp/reader.h"
|
||||
|
||||
#include "kvflickr.h"
|
||||
|
||||
class KVFlickrResponse : public LLHTTPClient::Responder
|
||||
{
|
||||
public:
|
||||
KVFlickrResponse(KVFlickrRequest::response_callback_t &callback);
|
||||
/* virtual */ void completedRaw(
|
||||
U32 status,
|
||||
const std::string& reason,
|
||||
const LLChannelDescriptors& channels,
|
||||
const LLIOPipe::buffer_ptr_t& buffer);
|
||||
private:
|
||||
KVFlickrRequest::response_callback_t mCallback;
|
||||
};
|
||||
|
||||
class KVFlickrUploadResponse : public LLHTTPClient::Responder
|
||||
{
|
||||
public:
|
||||
KVFlickrUploadResponse(KVFlickrRequest::response_callback_t &callback);
|
||||
/* virtual */ void completedRaw(
|
||||
U32 status,
|
||||
const std::string& reason,
|
||||
const LLChannelDescriptors& channels,
|
||||
const LLIOPipe::buffer_ptr_t& buffer);
|
||||
private:
|
||||
KVFlickrRequest::response_callback_t mCallback;
|
||||
};
|
||||
|
||||
void KVFlickrRequest::request(const std::string& method, const LLSD& args, response_callback_t callback)
|
||||
{
|
||||
LLSD params(args);
|
||||
params["format"] = "json";
|
||||
params["method"] = method;
|
||||
params["api_key"] = KV_FLICKR_API_KEY;
|
||||
params["nojsoncallback"] = 1;
|
||||
params["api_sig"] = getSignatureForCall(params, true); // This must be the last one set.
|
||||
LLHTTPClient::get("http://flickr.com/services/rest/", params, new KVFlickrResponse(callback));
|
||||
}
|
||||
|
||||
//static
|
||||
void KVFlickrRequest::uploadPhoto(const LLSD& args, LLImageFormatted *image, response_callback_t callback)
|
||||
{
|
||||
LLSD params(args);
|
||||
params["api_key"] = KV_FLICKR_API_KEY;
|
||||
params["api_sig"] = getSignatureForCall(params, false);
|
||||
|
||||
// It would be nice if there was an easy way to do multipart form data. Oh well.
|
||||
std::string boundary = "------------" + LLUUID::generateNewID().asString();
|
||||
std::ostringstream post_stream;
|
||||
post_stream << "--" << boundary;
|
||||
// Add all the parameters from LLSD to the query.
|
||||
for(LLSD::map_const_iterator itr = params.beginMap(); itr != params.endMap(); ++itr)
|
||||
{
|
||||
post_stream << "\r\nContent-Disposition: form-data; name=\"" << itr->first << "\"";
|
||||
post_stream << "\r\n\r\n" << itr->second.asString();
|
||||
post_stream << "\r\n" << "--" << boundary;
|
||||
}
|
||||
// Headers for the photo
|
||||
post_stream << "\r\nContent-Disposition: form-data; name=\"photo\"; filename=\"snapshot." << image->getExtension() << "\"";
|
||||
post_stream << "\r\nContent-Type: ";
|
||||
// Apparently LLImageFormatted doesn't know what mimetype it has.
|
||||
if(image->getExtension() == "jpg")
|
||||
{
|
||||
post_stream << "image/jpeg";
|
||||
}
|
||||
else if(image->getExtension() == "png")
|
||||
{
|
||||
post_stream << "image/png";
|
||||
}
|
||||
else // This will (probably) only happen if someone decides to put the BMP entry back in the format selection floater.
|
||||
{ // I wonder if Flickr would do the right thing.
|
||||
post_stream << "application/x-wtf";
|
||||
LL_WARNS("FlickrAPI") << "Uploading unknown image type." << LL_ENDL;
|
||||
}
|
||||
post_stream << "\r\n\r\n";
|
||||
|
||||
// Now we build the postdata array, including the photo in the middle of it.
|
||||
// C memory operations abound!
|
||||
std::string post_str = post_stream.str();
|
||||
size_t total_data_size = image->getDataSize() + post_str.length() + boundary.length() + 6; // + 6 = "\r\n" + "--" + "--"
|
||||
char* post_data = new char[total_data_size + 1];
|
||||
memcpy(post_data, post_str.data(), post_str.length());
|
||||
char* address = post_data + post_str.length();
|
||||
memcpy(address, image->getData(), image->getDataSize());
|
||||
address += image->getDataSize();
|
||||
std::string post_tail = "\r\n--" + boundary + "--";
|
||||
memcpy(address, post_tail.data(), post_tail.length());
|
||||
address += post_tail.length();
|
||||
llassert(address <= post_data + total_data_size /* After all that, check we didn't overrun */);
|
||||
|
||||
// We have a post body! Now we can go about building the actual request...
|
||||
LLSD headers;
|
||||
headers["Content-Type"] = "multipart/form-data; boundary=" + boundary;
|
||||
LLHTTPClient::postRaw("http://api.flickr.com/services/upload/", (U8*)post_data, total_data_size, new KVFlickrUploadResponse(callback), headers);
|
||||
// The HTTP client takes ownership of our post_data array,
|
||||
// and will delete it when it's done.
|
||||
}
|
||||
|
||||
//static
|
||||
std::string KVFlickrRequest::getSignatureForCall(const LLSD& parameters, bool encoded)
|
||||
{
|
||||
std::vector<std::string> keys;
|
||||
for(LLSD::map_const_iterator itr = parameters.beginMap(); itr != parameters.endMap(); ++itr)
|
||||
{
|
||||
keys.push_back(itr->first);
|
||||
}
|
||||
std::sort(keys.begin(), keys.end());
|
||||
std::string to_hash(KV_FLICKR_API_SECRET);
|
||||
for(std::vector<std::string>::const_iterator itr = keys.begin(); itr != keys.end(); ++itr)
|
||||
{
|
||||
to_hash += *itr;
|
||||
if(encoded)
|
||||
{
|
||||
to_hash += LLURI::escapeQueryValue(parameters[*itr].asString());
|
||||
}
|
||||
else
|
||||
{
|
||||
to_hash += parameters[*itr].asString();
|
||||
}
|
||||
}
|
||||
LLMD5 hashed((const unsigned char*)to_hash.c_str());
|
||||
char hex_hash[MD5HEX_STR_SIZE];
|
||||
hashed.hex_digest(hex_hash);
|
||||
return std::string(hex_hash);
|
||||
}
|
||||
|
||||
KVFlickrUploadResponse::KVFlickrUploadResponse(KVFlickrRequest::response_callback_t &callback)
|
||||
: mCallback(callback)
|
||||
{
|
||||
}
|
||||
|
||||
void KVFlickrUploadResponse::completedRaw(
|
||||
U32 status,
|
||||
const std::string& reason,
|
||||
const LLChannelDescriptors& channels,
|
||||
const LLIOPipe::buffer_ptr_t& buffer)
|
||||
{
|
||||
LLBufferStream istr(channels, buffer.get());
|
||||
std::stringstream strstrm;
|
||||
strstrm << istr.rdbuf();
|
||||
std::string result = std::string(strstrm.str());
|
||||
|
||||
LLSD output;
|
||||
bool success;
|
||||
|
||||
LLXmlTree tree;
|
||||
if(!tree.parseString(result))
|
||||
{
|
||||
LL_WARNS("FlickrAPI") << "Couldn't parse flickr response: " << result << LL_ENDL;
|
||||
mCallback(false, LLSD());
|
||||
return;
|
||||
}
|
||||
LLXmlTreeNode* root = tree.getRoot();
|
||||
if(!root->hasName("rsp"))
|
||||
{
|
||||
LL_WARNS("FlickrAPI") << "Bad root node: " << root->getName() << LL_ENDL;
|
||||
mCallback(false, LLSD());
|
||||
return;
|
||||
}
|
||||
std::string stat;
|
||||
root->getAttributeString("stat", stat);
|
||||
output["stat"] = stat;
|
||||
if(stat == "ok")
|
||||
{
|
||||
success = true;
|
||||
LLXmlTreeNode* photoid_node = root->getChildByName("photoid");
|
||||
if(photoid_node)
|
||||
{
|
||||
output["photoid"] = photoid_node->getContents();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
success = false;
|
||||
LLXmlTreeNode* err_node = root->getChildByName("err");
|
||||
if(err_node)
|
||||
{
|
||||
S32 code;
|
||||
std::string msg;
|
||||
err_node->getAttributeS32("code", code);
|
||||
err_node->getAttributeString("msg", msg);
|
||||
output["code"] = code;
|
||||
output["msg"] = msg;
|
||||
}
|
||||
}
|
||||
mCallback(success, output);
|
||||
}
|
||||
|
||||
void JsonToLLSD(const Json::Value &root, LLSD &output)
|
||||
{
|
||||
if(root.isObject())
|
||||
{
|
||||
Json::Value::Members keys = root.getMemberNames();
|
||||
for(Json::Value::Members::const_iterator itr = keys.begin(); itr != keys.end(); ++itr)
|
||||
{
|
||||
LLSD elem;
|
||||
JsonToLLSD(root[*itr], elem);
|
||||
output[*itr] = elem;
|
||||
}
|
||||
}
|
||||
else if(root.isArray())
|
||||
{
|
||||
for(Json::Value::const_iterator itr = root.begin(); itr != root.end(); ++itr)
|
||||
{
|
||||
LLSD elem;
|
||||
JsonToLLSD(*itr, elem);
|
||||
output.append(elem);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch(root.type())
|
||||
{
|
||||
case Json::intValue:
|
||||
output = root.asInt();
|
||||
break;
|
||||
case Json::realValue:
|
||||
case Json::uintValue:
|
||||
output = root.asDouble();
|
||||
break;
|
||||
case Json::stringValue:
|
||||
output = root.asString();
|
||||
break;
|
||||
case Json::booleanValue:
|
||||
output = root.asBool();
|
||||
case Json::nullValue:
|
||||
output = NULL;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
KVFlickrResponse::KVFlickrResponse(KVFlickrRequest::response_callback_t &callback) :
|
||||
mCallback(callback)
|
||||
{
|
||||
}
|
||||
|
||||
void KVFlickrResponse::completedRaw(
|
||||
U32 status,
|
||||
const std::string& reason,
|
||||
const LLChannelDescriptors& channels,
|
||||
const LLIOPipe::buffer_ptr_t& buffer)
|
||||
{
|
||||
LLBufferStream istr(channels, buffer.get());
|
||||
std::stringstream strstrm;
|
||||
strstrm << istr.rdbuf();
|
||||
std::string result = std::string(strstrm.str());
|
||||
Json::Value root;
|
||||
Json::Reader reader;
|
||||
|
||||
bool success = reader.parse(result, root);
|
||||
if(!success)
|
||||
{
|
||||
mCallback(false, LLSD());
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_INFOS("FlickrAPI") << "Got response string: " << result << LL_ENDL;
|
||||
LLSD response;
|
||||
JsonToLLSD(root, response);
|
||||
LL_INFOS("FlickrAPI") << "As LLSD: " << response << LL_ENDL;
|
||||
mCallback(isGoodStatus(status), response);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
/**
|
||||
* @file kvflickr.h
|
||||
* @brief Basic Flickr library for the client.
|
||||
* @copyright Copyright (c) 2011 Katharine Berry
|
||||
*
|
||||
* 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; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
#ifndef KV_KVFLICKR_H
|
||||
#define KV_KVFLICKR_H
|
||||
|
||||
#include "llimage.h"
|
||||
#include "llsd.h"
|
||||
|
||||
#include <boost/bind.hpp>
|
||||
|
||||
// This include file defines the API key/secret.
|
||||
// It is generated by cmake.
|
||||
#include "kvflickrkeys.h"
|
||||
|
||||
class KVFlickrRequest
|
||||
{
|
||||
public:
|
||||
typedef boost::function<void(bool success, const LLSD& response)> response_callback_t;
|
||||
|
||||
static void request(const std::string& method, const LLSD& args, response_callback_t callback);
|
||||
static void uploadPhoto(const LLSD& args, LLImageFormatted *image, response_callback_t callback);
|
||||
static std::string getSignatureForCall(const LLSD& parameters, bool encoded);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
// THIS FILE IS AUTOGENERATED BY THE BUILD PROCESS.
|
||||
// Set the Flickr keys in Variables.cmake or on the develop.py command line.
|
||||
|
||||
#define KV_FLICKR_API_KEY "@FLICKR_API_KEY@"
|
||||
#define KV_FLICKR_API_SECRET "@FLICKR_API_SECRET@"
|
||||
|
|
@ -0,0 +1,154 @@
|
|||
/**
|
||||
* @file kvfloaterflickrauth.cpp
|
||||
* @brief Flickr authentication floater
|
||||
* @copyright Copyright (c) 2011 Katharine Berry
|
||||
*
|
||||
* 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; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
#include "llviewerprecompiledheaders.h"
|
||||
|
||||
#include "llfloaterreg.h"
|
||||
#include "llsd.h"
|
||||
#include "llslurl.h"
|
||||
#include "lluri.h"
|
||||
#include "llurlaction.h"
|
||||
#include "llviewercontrol.h"
|
||||
|
||||
#include "kvflickr.h"
|
||||
#include "kvfloaterflickrauth.h"
|
||||
|
||||
KVFloaterFlickrAuth::KVFloaterFlickrAuth(const LLSD& key) :
|
||||
LLFloater(key), mCallback(NULL), mBrowser(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
BOOL KVFloaterFlickrAuth::postBuild()
|
||||
{
|
||||
mBrowser = getChild<LLMediaCtrl>("browser");
|
||||
mBrowser->addObserver(this);
|
||||
|
||||
// Work out URL.
|
||||
LLSD query;
|
||||
query["api_key"] = std::string(KV_FLICKR_API_KEY);
|
||||
query["perms"] = "write";
|
||||
query["api_sig"] = KVFlickrRequest::getSignatureForCall(query, true);
|
||||
std::string query_string = LLURI::mapToQueryString(query);
|
||||
LL_INFOS("FlickrAPI") << "Auth query: " << query_string << LL_ENDL;
|
||||
std::string full_url = "http://www.flickr.com/services/auth/" + query_string;
|
||||
mBrowser->navigateTo(full_url, "text/html");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void KVFloaterFlickrAuth::onClose(bool app_quitting)
|
||||
{
|
||||
// If we still have an mCallback here, we know it wasn't successful,
|
||||
// because we always set it to NULL after using it.
|
||||
if(mCallback)
|
||||
{
|
||||
mCallback(false);
|
||||
mCallback = NULL;
|
||||
}
|
||||
destroy(); // Die die die!
|
||||
}
|
||||
|
||||
void KVFloaterFlickrAuth::handleMediaEvent(LLPluginClassMedia* media, EMediaEvent event)
|
||||
{
|
||||
if(event == MEDIA_EVENT_LOCATION_CHANGED)
|
||||
{
|
||||
std::string uri_string = media->getLocation();
|
||||
LLURI uri(uri_string);
|
||||
// We use this moronic data: hack because the internal browser crashes on
|
||||
// secondlife:/// redirects, doesn't raise any events on nonexistent links,
|
||||
// and gets confused by about:blank. At least this is prettier.
|
||||
if(uri.scheme() == "data")
|
||||
{
|
||||
// Turns out we have to parse query string out ourselves because LLURI won't do it
|
||||
// unless it's a http(s), ftp, secondlife or x-grid-location-info link.
|
||||
std::string::size_type q = uri_string.find('?');
|
||||
if(q != std::string::npos)
|
||||
{
|
||||
std::string query_string = uri_string.substr(q + 1);
|
||||
LLSD query = LLURI::queryMap(query_string);
|
||||
if(query.has("frob"))
|
||||
{
|
||||
std::string frob = query["frob"];
|
||||
LLSD params;
|
||||
params["frob"] = frob;
|
||||
KVFlickrRequest::request("flickr.auth.getToken", params, boost::bind(&KVFloaterFlickrAuth::gotToken, this, _1, _2));
|
||||
}
|
||||
}
|
||||
}
|
||||
// We don't get anything if authentication is rejected; they're just redirected to the
|
||||
// home page. This is mildly problematic, given the restricted view they're in.
|
||||
// Therefore, if they click outside where we want them to be, we close the view.
|
||||
// If they go to the homepage (because they clicked "Home", the logo, or (most importantly)
|
||||
// the "Do not allow" button), it is noted that they refused permission. Otherwise,
|
||||
// we open the link they clicked in a standard browser. In either case we close
|
||||
// our floater.
|
||||
else if(uri.hostName() == "www.flickr.com" && uri.path() != "/services/auth/")
|
||||
{
|
||||
LL_WARNS("FlickrAPI") << "API permission not granted." << LL_ENDL;
|
||||
if(uri.path() != "/")
|
||||
{
|
||||
LLUrlAction::openURL(uri_string);
|
||||
}
|
||||
closeFloater(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void KVFloaterFlickrAuth::gotToken(bool success, const LLSD& response)
|
||||
{
|
||||
std::string token = response["auth"]["token"]["_content"];
|
||||
std::string username = response["auth"]["user"]["username"];
|
||||
std::string nsid = response["auth"]["user"]["nsid"];
|
||||
LL_INFOS("FlickrAPI") << "Got token " << token << " for user " << username << " (" << nsid << ")." << LL_ENDL;
|
||||
gSavedPerAccountSettings.setString("KittyFlickrToken", token);
|
||||
gSavedPerAccountSettings.setString("KittyFlickrUsername", username);
|
||||
gSavedPerAccountSettings.setString("KittyFlickrNSID", nsid);
|
||||
if(mCallback)
|
||||
{
|
||||
mCallback((token != ""));
|
||||
mCallback = NULL;
|
||||
}
|
||||
closeFloater(false);
|
||||
}
|
||||
|
||||
//static
|
||||
KVFloaterFlickrAuth* KVFloaterFlickrAuth::showFloater()
|
||||
{
|
||||
return KVFloaterFlickrAuth::showFloater(NULL);
|
||||
}
|
||||
|
||||
//static
|
||||
KVFloaterFlickrAuth* KVFloaterFlickrAuth::showFloater(auth_callback_t callback)
|
||||
{
|
||||
KVFloaterFlickrAuth *floater = dynamic_cast<KVFloaterFlickrAuth*>(LLFloaterReg::getInstance("flickr_auth"));
|
||||
if(floater)
|
||||
{
|
||||
floater->mCallback = callback;
|
||||
floater->setVisible(true);
|
||||
floater->setFrontmost(true);
|
||||
floater->center();
|
||||
return floater;
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_WARNS("FlickrAPI") << "Can't find flickr auth!" << LL_ENDL;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
/**
|
||||
* @file kvfloaterflickrauth.h
|
||||
* @brief Flickr authentication floater
|
||||
* @copyright Copyright (c) 2011 Katharine Berry
|
||||
*
|
||||
* 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; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
#ifndef KV_KVFLOATERFLICKRAUTH_H
|
||||
#define KV_KVFLOATERFLICKRAUTH_H
|
||||
|
||||
#include "llfloater.h"
|
||||
#include "llmediactrl.h"
|
||||
|
||||
#include <boost/bind.hpp>
|
||||
|
||||
class KVFloaterFlickrAuth :
|
||||
public LLFloater,
|
||||
public LLViewerMediaObserver
|
||||
{
|
||||
public:
|
||||
typedef boost::function<void(bool)> auth_callback_t;
|
||||
|
||||
KVFloaterFlickrAuth(const LLSD& key);
|
||||
|
||||
/*virtual*/ BOOL postBuild();
|
||||
/*virtual*/ void onClose(bool app_quitting);
|
||||
|
||||
// inherited from LLViewerMediaObserver
|
||||
/*virtual*/ void handleMediaEvent(LLPluginClassMedia* media, EMediaEvent event);
|
||||
|
||||
static KVFloaterFlickrAuth* showFloater();
|
||||
static KVFloaterFlickrAuth* showFloater(auth_callback_t callback);
|
||||
|
||||
private:
|
||||
void gotToken(bool success, const LLSD& response);
|
||||
LLMediaCtrl* mBrowser;
|
||||
auth_callback_t mCallback;
|
||||
};
|
||||
|
||||
#endif // KV_KVFLOATERFLICKRAUTH_H
|
||||
|
|
@ -0,0 +1,325 @@
|
|||
/**
|
||||
* @file kvfloaterflickrupload.cpp
|
||||
* @brief Flickr upload floater
|
||||
* @copyright Copyright (c) 2011 Katharine Berry
|
||||
*
|
||||
* 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; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
#include "llviewerprecompiledheaders.h"
|
||||
|
||||
#include "kvfloaterflickrupload.h"
|
||||
|
||||
#include "llagent.h"
|
||||
#include "llfloaterreg.h"
|
||||
#include "llfloatersnapshot.h"
|
||||
#include "llgl.h"
|
||||
#include "llimage.h"
|
||||
#include "llnotificationsutil.h"
|
||||
#include "llslurl.h"
|
||||
#include "llui.h"
|
||||
#include "lluploaddialog.h"
|
||||
#include "llviewercontrol.h"
|
||||
#include "llviewerregion.h"
|
||||
#include "llviewertexture.h"
|
||||
#include "llworld.h"
|
||||
|
||||
#include "kvflickr.h"
|
||||
#include "kvfloaterflickrauth.h"
|
||||
|
||||
#include <boost/bind.hpp>
|
||||
|
||||
KVFloaterFlickrUpload::KVFloaterFlickrUpload(const LLSD& key) : LLFloater(key),
|
||||
mCompressedImage(NULL),
|
||||
mViewerImage(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
KVFloaterFlickrUpload::~KVFloaterFlickrUpload()
|
||||
{
|
||||
mCompressedImage = NULL;
|
||||
mViewerImage = NULL;
|
||||
}
|
||||
|
||||
// static
|
||||
KVFloaterFlickrUpload* KVFloaterFlickrUpload::showFromSnapshot(LLImageFormatted *compressed, LLViewerTexture *img, const LLVector2& img_scale, const LLVector3d& pos_taken_global)
|
||||
{
|
||||
// Take the images from the caller
|
||||
// It's now our job to clean them up
|
||||
KVFloaterFlickrUpload* instance = LLFloaterReg::showTypedInstance<KVFloaterFlickrUpload>("flickr_upload", LLSD(img->getID()));
|
||||
|
||||
instance->mCompressedImage = compressed;
|
||||
instance->mViewerImage = img;
|
||||
instance->mImageScale = img_scale;
|
||||
instance->mPosTakenGlobal = pos_taken_global;
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
BOOL KVFloaterFlickrUpload::postBuild()
|
||||
{
|
||||
// Set the various UI fields to their default values.
|
||||
childSetValue("rating_combo", gSavedSettings.getLLSD("KittyFlickrLastRating"));
|
||||
childSetValue("tags_form", gSavedSettings.getLLSD("KittyFlickrLastTags"));
|
||||
childSetValue("show_position_check", gSavedSettings.getLLSD("KittyFlickrShowPosition"));
|
||||
|
||||
// Connect the buttons up
|
||||
childSetAction("cancel_btn", onClickCancel, this);
|
||||
childSetAction("upload_btn", onClickUpload, this);
|
||||
|
||||
// Check that we actually can do an upload.
|
||||
LLSD query;
|
||||
query["auth_token"] = gSavedPerAccountSettings.getLLSD("KittyFlickrToken");
|
||||
KVFlickrRequest::request("flickr.auth.checkToken", query, boost::bind(&KVFloaterFlickrUpload::confirmToken, this, _1, _2));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void KVFloaterFlickrUpload::confirmToken(bool success, const LLSD &response)
|
||||
{
|
||||
if(!success)
|
||||
{
|
||||
LLNotificationsUtil::add("KittyFlickrHTTPFail");
|
||||
closeFloater(false);
|
||||
return;
|
||||
}
|
||||
if(response["stat"].asString() == "ok")
|
||||
{
|
||||
// Just in case the username changed. This can happen.
|
||||
std::string username = response["auth"]["user"]["username"];
|
||||
gSavedPerAccountSettings.setString("KittyFlickrUsername", username);
|
||||
childSetValue("account_name", username);
|
||||
childSetEnabled("upload_btn", true);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Uh oh.
|
||||
if(response["code"].asInteger() == 98) // Invalid auth token
|
||||
{
|
||||
// Mark the account as invalid
|
||||
childSetValue("account_name", getString("no_account"));
|
||||
// Need to authenticate.
|
||||
gSavedPerAccountSettings.setString("KittyFlickrToken", "");
|
||||
gSavedPerAccountSettings.setString("KittyFlickrUsername", "");
|
||||
gSavedPerAccountSettings.setString("KittyFlickrNSID", "");
|
||||
KVFloaterFlickrAuth *floater = KVFloaterFlickrAuth::showFloater(boost::bind(&KVFloaterFlickrUpload::authCallback, this, _1));
|
||||
// Link it to us to protect it from freeze frame mode, if need be.
|
||||
if(floater && getDependee()) // (if we're depending on something, so should it)
|
||||
{
|
||||
gFloaterView->removeChild(floater);
|
||||
gSnapshotFloaterView->addChild(floater);
|
||||
// Even though we don't really want this to depend on the snapshot view
|
||||
// being open, if we manipulate it after closing the snapshot view,
|
||||
// it will crash.
|
||||
getDependee()->addDependentFloater(floater, false);
|
||||
}
|
||||
LLNotificationsUtil::add("KittyFlickrTokenRejected");
|
||||
}
|
||||
else
|
||||
{
|
||||
LLSD args;
|
||||
args["CODE"] = response["code"];
|
||||
args["ERROR"] = response["message"];
|
||||
LLNotificationsUtil::add("KittyFlickrGenericFail", args);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void KVFloaterFlickrUpload::authCallback(bool authorised)
|
||||
{
|
||||
if(authorised)
|
||||
{
|
||||
childSetValue("account_name", gSavedPerAccountSettings.getString("KittyFlickrUsername"));
|
||||
childSetEnabled("upload_btn", true);
|
||||
}
|
||||
else
|
||||
{
|
||||
LLNotificationsUtil::add("KittyFlickrUploadCancelledAuthRejected");
|
||||
closeFloater(false);
|
||||
}
|
||||
}
|
||||
|
||||
void KVFloaterFlickrUpload::saveSettings()
|
||||
{
|
||||
gSavedSettings.setS32("KittyFlickrLastRating", childGetValue("rating_combo"));
|
||||
gSavedSettings.setString("KittyFlickrLastTags", childGetValue("tags_form"));
|
||||
gSavedSettings.setBOOL("KittyFlickrShowPosition", childGetValue("show_position_check"));
|
||||
}
|
||||
|
||||
void KVFloaterFlickrUpload::uploadSnapshot()
|
||||
{
|
||||
mTitle = childGetValue("title_form").asString();
|
||||
LLSD params;
|
||||
params["title"] = childGetValue("title_form");
|
||||
params["safety_level"] = childGetValue("rating_combo");
|
||||
std::string tags = childGetValue("tags_form");
|
||||
std::string description = childGetValue("description_form");
|
||||
if(childGetValue("show_position_check").asBoolean())
|
||||
{
|
||||
// Work out where this was taken.
|
||||
LLVector3d clamped_global = LLWorld::getInstance()->clipToVisibleRegions(gAgent.getPositionGlobal(), mPosTakenGlobal);
|
||||
LLViewerRegion* region = LLWorld::getInstance()->getRegionFromPosGlobal(clamped_global);
|
||||
if(!region)
|
||||
{
|
||||
// Clamping failed? Shouldn't happen.
|
||||
// Use the agent's position instead; if the region the agent is in doesn't exist we have some serious issues,
|
||||
// and crashing is an entirely reasonable thing to do.
|
||||
region = gAgent.getRegion();
|
||||
clamped_global = gAgent.getPositionGlobal();
|
||||
}
|
||||
std::string region_name = region->getName();
|
||||
LLVector3 region_pos = region->getPosRegionFromGlobal(clamped_global);
|
||||
std::ostringstream region_tags;
|
||||
region_tags << " \"secondlife:region=" << region_name << "\"";
|
||||
region_tags << " secondlife:x=" << llround(region_pos[VX]);
|
||||
region_tags << " secondlife:y=" << llround(region_pos[VY]);
|
||||
region_tags << " secondlife:z=" << llround(region_pos[VZ]);
|
||||
|
||||
// Now let's give some precise camera values.
|
||||
region_tags << " secondlife:camera_pos_x=" << (mPosTakenGlobal[VX] - region->getOriginGlobal()[VX]);
|
||||
region_tags << " secondlife:camera_pos_y=" << (mPosTakenGlobal[VY] - region->getOriginGlobal()[VY]);
|
||||
region_tags << " secondlife:camera_pos_z=" << mPosTakenGlobal[VZ];
|
||||
tags += region_tags.str();
|
||||
|
||||
// Include an SLurl in the description, too (maybe).
|
||||
if(gSavedSettings.getBOOL("KittyFlickrIncludeSLURL"))
|
||||
{
|
||||
LLSLURL url(region_name, region_pos);
|
||||
std::ostringstream region_desc;
|
||||
region_desc << "<em><a href='" << url.getSLURLString() << "'>";
|
||||
region_desc << "Taken at " << region_name << " (";
|
||||
region_desc << llround(region_pos[VX]) << ", ";
|
||||
region_desc << llround(region_pos[VY]) << ", ";
|
||||
region_desc << llround(region_pos[VZ]) << ")";
|
||||
region_desc << "</a></em>";
|
||||
if(description != "")
|
||||
{
|
||||
description += "\n\n";
|
||||
}
|
||||
description += region_desc.str();
|
||||
}
|
||||
}
|
||||
params["tags"] = tags;
|
||||
params["description"] = description;
|
||||
LL_INFOS("FlickrAPI") << "Uploading snapshot with metadata: " << params << LL_ENDL;
|
||||
|
||||
params["auth_token"] = gSavedPerAccountSettings.getLLSD("KittyFlickrToken");
|
||||
LLUploadDialog::modalUploadDialog(getString("uploading"));
|
||||
KVFlickrRequest::uploadPhoto(params, mCompressedImage, boost::bind(&KVFloaterFlickrUpload::imageUploaded, this, _1, _2));
|
||||
}
|
||||
|
||||
void KVFloaterFlickrUpload::imageUploaded(bool success, const LLSD& response)
|
||||
{
|
||||
LLUploadDialog::modalUploadFinished();
|
||||
LLSD args;
|
||||
args["TITLE"] = mTitle;
|
||||
if(success)
|
||||
{
|
||||
args["ID"] = response["photoid"];
|
||||
LLNotificationsUtil::add("KittyFlickrUploadComplete", args);
|
||||
}
|
||||
else if(response.has("stat"))
|
||||
{
|
||||
args["CODE"] = response["code"];
|
||||
args["ERROR"] = response["msg"];
|
||||
LLNotificationsUtil::add("KittyFlickrUploadFailed", args);
|
||||
}
|
||||
else
|
||||
{
|
||||
LLNotificationsUtil::add("KittyFlickrUploadFailedNoError");
|
||||
}
|
||||
|
||||
// We're pretty much done now.
|
||||
closeFloater(false);
|
||||
}
|
||||
|
||||
// This function stolen from LLFloaterPostcard
|
||||
void KVFloaterFlickrUpload::draw()
|
||||
{
|
||||
LLGLSUIDefault gls_ui;
|
||||
LLFloater::draw();
|
||||
|
||||
if(!isMinimized() && mViewerImage.notNull() && mCompressedImage.notNull())
|
||||
{
|
||||
LLRect rect(getRect());
|
||||
|
||||
// first set the max extents of our preview
|
||||
rect.translate(-rect.mLeft, -rect.mBottom);
|
||||
rect.mLeft += 280;
|
||||
rect.mRight -= 10;
|
||||
rect.mTop -= 27;
|
||||
rect.mBottom = rect.mTop - 130;
|
||||
|
||||
// then fix the aspect ratio
|
||||
F32 ratio = (F32)mCompressedImage->getWidth() / (F32)mCompressedImage->getHeight();
|
||||
if ((F32)rect.getWidth() / (F32)rect.getHeight() >= ratio)
|
||||
{
|
||||
rect.mRight = LLRect::tCoordType((F32)rect.mLeft + ((F32)rect.getHeight() * ratio));
|
||||
}
|
||||
else
|
||||
{
|
||||
rect.mBottom = LLRect::tCoordType((F32)rect.mTop - ((F32)rect.getWidth() / ratio));
|
||||
}
|
||||
{
|
||||
gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
|
||||
gl_rect_2d(rect, LLColor4(0.f, 0.f, 0.f, 1.f));
|
||||
rect.stretch(-1);
|
||||
}
|
||||
{
|
||||
|
||||
glMatrixMode(GL_TEXTURE);
|
||||
glPushMatrix();
|
||||
{
|
||||
glScalef(mImageScale.mV[VX], mImageScale.mV[VY], 1.f);
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
gl_draw_scaled_image(rect.mLeft,
|
||||
rect.mBottom,
|
||||
rect.getWidth(),
|
||||
rect.getHeight(),
|
||||
mViewerImage.get(),
|
||||
LLColor4::white);
|
||||
}
|
||||
glMatrixMode(GL_TEXTURE);
|
||||
glPopMatrix();
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//static
|
||||
void KVFloaterFlickrUpload::onClickCancel(void* data)
|
||||
{
|
||||
if(data)
|
||||
{
|
||||
KVFloaterFlickrUpload *self = (KVFloaterFlickrUpload*)data;
|
||||
self->closeFloater(false);
|
||||
}
|
||||
}
|
||||
|
||||
//static
|
||||
void KVFloaterFlickrUpload::onClickUpload(void* data)
|
||||
{
|
||||
if(!data)
|
||||
return;
|
||||
KVFloaterFlickrUpload *self = (KVFloaterFlickrUpload*)data;
|
||||
self->uploadSnapshot();
|
||||
self->saveSettings();
|
||||
self->setVisible(false);
|
||||
// Make sure that, if we were attached to anything, that we detach from it.
|
||||
// Otherwise bad things happen.
|
||||
LLFloater *dependee = self->getDependee();
|
||||
if(dependee)
|
||||
dependee->removeDependentFloater(self);
|
||||
}
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
/**
|
||||
* @file kvfloaterflickrupload.h
|
||||
* @brief Flickr upload floater
|
||||
* @copyright Copyright (c) 2011 Katharine Berry
|
||||
*
|
||||
* 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; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
#ifndef KV_KVFLOATERFLICKRUPLOAD_H
|
||||
#define KV_KVFLOATERFLICKRUPLOAD_H
|
||||
|
||||
#include "llfloater.h"
|
||||
#include "llcheckboxctrl.h"
|
||||
|
||||
#include "llpointer.h"
|
||||
|
||||
class LLViewerTexture;
|
||||
class LLImageFormatted;
|
||||
|
||||
class KVFloaterFlickrUpload : public LLFloater
|
||||
{
|
||||
public:
|
||||
KVFloaterFlickrUpload(const LLSD& key);
|
||||
~KVFloaterFlickrUpload();
|
||||
|
||||
BOOL postBuild();
|
||||
void draw();
|
||||
void saveSettings();
|
||||
void uploadSnapshot();
|
||||
|
||||
void confirmToken(bool success, const LLSD &response);
|
||||
void authCallback(bool authorised);
|
||||
void imageUploaded(bool success, const LLSD& response);
|
||||
|
||||
static void onClickCancel(void* data);
|
||||
static void onClickUpload(void* data);
|
||||
static KVFloaterFlickrUpload* showFromSnapshot(LLImageFormatted *compressed, LLViewerTexture *img, const LLVector2& img_scale, const LLVector3d& pos_taken_global);
|
||||
|
||||
private:
|
||||
LLPointer<LLImageFormatted> mCompressedImage;
|
||||
LLPointer<LLViewerTexture> mViewerImage;
|
||||
LLVector2 mImageScale;
|
||||
LLVector3d mPosTakenGlobal;
|
||||
std::string mTitle; // Used in the confirmation announcement.
|
||||
};
|
||||
|
||||
|
||||
#endif // KV_KVFLOATERFLICKRUPLOAD_H
|
||||
|
|
@ -59,6 +59,9 @@
|
|||
#include "llworld.h"
|
||||
#include "llagentui.h"
|
||||
|
||||
#include "kvfloaterflickrauth.h"
|
||||
#include "kvfloaterflickrupload.h"
|
||||
|
||||
// Linden library includes
|
||||
#include "llfontgl.h"
|
||||
#include "llsys.h"
|
||||
|
|
@ -113,7 +116,8 @@ public:
|
|||
SNAPSHOT_POSTCARD,
|
||||
SNAPSHOT_TEXTURE,
|
||||
SNAPSHOT_LOCAL,
|
||||
SNAPSHOT_WEB
|
||||
SNAPSHOT_WEB,
|
||||
SNAPSHOT_FLICKR
|
||||
};
|
||||
|
||||
|
||||
|
|
@ -161,6 +165,7 @@ public:
|
|||
void updateSnapshot(BOOL new_snapshot, BOOL new_thumbnail = FALSE, F32 delay = 0.f);
|
||||
void saveWeb();
|
||||
LLFloaterPostcard* savePostcard();
|
||||
KVFloaterFlickrUpload* uploadToFlickr();
|
||||
void saveTexture();
|
||||
BOOL saveLocal();
|
||||
|
||||
|
|
@ -967,6 +972,24 @@ LLFloaterPostcard* LLSnapshotLivePreview::savePostcard()
|
|||
return floater;
|
||||
}
|
||||
|
||||
KVFloaterFlickrUpload* LLSnapshotLivePreview::uploadToFlickr()
|
||||
{
|
||||
// calculate and pass in image scale in case image data only use portion
|
||||
// of viewerimage buffer
|
||||
LLVector2 image_scale(1.f, 1.f);
|
||||
if (!isImageScaled())
|
||||
{
|
||||
image_scale.setVec(llmin(1.f, (F32)mWidth[mCurImageIndex] / (F32)getCurrentImage()->getWidth()), llmin(1.f, (F32)mHeight[mCurImageIndex] / (F32)getCurrentImage()->getHeight()));
|
||||
}
|
||||
|
||||
KVFloaterFlickrUpload* floater = KVFloaterFlickrUpload::showFromSnapshot(mFormattedImage, mViewerImage[mCurImageIndex], image_scale, mPosTakenGlobal);
|
||||
mFormattedImage = NULL;
|
||||
mDataSize = 0;
|
||||
updateSnapshot(FALSE, FALSE);
|
||||
|
||||
return floater;
|
||||
}
|
||||
|
||||
void LLSnapshotLivePreview::saveTexture()
|
||||
{
|
||||
// gen a new uuid for this asset
|
||||
|
|
@ -1155,6 +1178,10 @@ LLSnapshotLivePreview::ESnapshotType LLFloaterSnapshot::Impl::getTypeIndex(LLFlo
|
|||
{
|
||||
index = LLSnapshotLivePreview::SNAPSHOT_WEB;
|
||||
}
|
||||
else if (id == "flickr")
|
||||
{
|
||||
index = LLSnapshotLivePreview::SNAPSHOT_FLICKR;
|
||||
}
|
||||
|
||||
return index;
|
||||
}
|
||||
|
|
@ -1174,6 +1201,9 @@ LLSD LLFloaterSnapshot::Impl::getTypeName(LLSnapshotLivePreview::ESnapshotType i
|
|||
case LLSnapshotLivePreview::SNAPSHOT_TEXTURE:
|
||||
id = "texture";
|
||||
break;
|
||||
case LLSnapshotLivePreview::SNAPSHOT_FLICKR:
|
||||
id = "flickr";
|
||||
break;
|
||||
case LLSnapshotLivePreview::SNAPSHOT_LOCAL:
|
||||
default:
|
||||
id = "local";
|
||||
|
|
@ -1186,10 +1216,10 @@ LLSD LLFloaterSnapshot::Impl::getTypeName(LLSnapshotLivePreview::ESnapshotType i
|
|||
LLFloaterSnapshot::ESnapshotFormat LLFloaterSnapshot::Impl::getFormatIndex(LLFloaterSnapshot* floater)
|
||||
{
|
||||
ESnapshotFormat index = SNAPSHOT_FORMAT_PNG;
|
||||
if(floater->hasChild("local_format_combo"))
|
||||
if(floater->hasChild("format_combo"))
|
||||
{
|
||||
LLComboBox* local_format_combo = floater->findChild<LLComboBox>("local_format_combo");
|
||||
const std::string id = local_format_combo->getSelectedItemLabel();
|
||||
LLComboBox* format_combo = floater->findChild<LLComboBox>("format_combo");
|
||||
const std::string id = format_combo->getSelectedItemLabel();
|
||||
if (id == "PNG")
|
||||
index = SNAPSHOT_FORMAT_PNG;
|
||||
else if (id == "JPEG")
|
||||
|
|
@ -1330,12 +1360,13 @@ void LLFloaterSnapshot::Impl::updateControls(LLFloaterSnapshot* floater)
|
|||
floater->getChild<LLComboBox>("postcard_size_combo")->selectNthItem(gSavedSettings.getS32("SnapshotPostcardLastResolution"));
|
||||
floater->getChild<LLComboBox>("texture_size_combo")->selectNthItem(gSavedSettings.getS32("SnapshotTextureLastResolution"));
|
||||
floater->getChild<LLComboBox>("local_size_combo")->selectNthItem(gSavedSettings.getS32("SnapshotLocalLastResolution"));
|
||||
floater->getChild<LLComboBox>("local_format_combo")->selectNthItem(gSavedSettings.getS32("SnapshotFormat"));
|
||||
floater->getChild<LLComboBox>("format_combo")->selectNthItem(gSavedSettings.getS32("SnapshotFormat"));
|
||||
|
||||
// *TODO: Separate settings for Web images from postcards
|
||||
floater->getChildView("send_btn")->setVisible( shot_type == LLSnapshotLivePreview::SNAPSHOT_POSTCARD ||
|
||||
shot_type == LLSnapshotLivePreview::SNAPSHOT_WEB);
|
||||
floater->getChildView("upload_btn")->setVisible(shot_type == LLSnapshotLivePreview::SNAPSHOT_TEXTURE);
|
||||
floater->getChildView("upload_btn")->setVisible(shot_type == LLSnapshotLivePreview::SNAPSHOT_TEXTURE ||
|
||||
shot_type == LLSnapshotLivePreview::SNAPSHOT_FLICKR);
|
||||
floater->getChildView("save_btn")->setVisible( shot_type == LLSnapshotLivePreview::SNAPSHOT_LOCAL);
|
||||
floater->getChildView("keep_aspect_check")->setEnabled(shot_type != LLSnapshotLivePreview::SNAPSHOT_TEXTURE && !floater->impl.mAspectRatioCheckOff);
|
||||
floater->getChildView("layer_types")->setEnabled(shot_type == LLSnapshotLivePreview::SNAPSHOT_LOCAL);
|
||||
|
|
@ -1347,16 +1378,17 @@ void LLFloaterSnapshot::Impl::updateControls(LLFloaterSnapshot* floater)
|
|||
floater->childSetEnabled("temp_check", shot_type == LLSnapshotLivePreview::SNAPSHOT_TEXTURE);
|
||||
|
||||
BOOL is_advance = gSavedSettings.getBOOL("AdvanceSnapshot");
|
||||
BOOL is_local = shot_type == LLSnapshotLivePreview::SNAPSHOT_LOCAL;
|
||||
BOOL can_choose_format = (shot_type == LLSnapshotLivePreview::SNAPSHOT_LOCAL ||
|
||||
shot_type == LLSnapshotLivePreview::SNAPSHOT_FLICKR);
|
||||
BOOL show_slider = (shot_type == LLSnapshotLivePreview::SNAPSHOT_POSTCARD ||
|
||||
shot_type == LLSnapshotLivePreview::SNAPSHOT_WEB ||
|
||||
(is_local && shot_format == LLFloaterSnapshot::SNAPSHOT_FORMAT_JPEG));
|
||||
(can_choose_format && shot_format == LLFloaterSnapshot::SNAPSHOT_FORMAT_JPEG));
|
||||
|
||||
floater->getChildView("more_btn")->setVisible( !is_advance); // the only item hidden in advanced mode
|
||||
floater->getChildView("less_btn")->setVisible( is_advance);
|
||||
floater->getChildView("type_label2")->setVisible( is_advance);
|
||||
floater->getChildView("format_label")->setVisible( is_advance && is_local);
|
||||
floater->getChildView("local_format_combo")->setVisible( is_advance && is_local);
|
||||
floater->getChildView("format_label")->setVisible(is_advance && can_choose_format);
|
||||
floater->getChildView("format_combo")->setVisible(is_advance && can_choose_format);
|
||||
floater->getChildView("layer_types")->setVisible( is_advance);
|
||||
floater->getChildView("layer_type_label")->setVisible( is_advance);
|
||||
floater->getChildView("snapshot_width")->setVisible( is_advance);
|
||||
|
|
@ -1407,7 +1439,8 @@ void LLFloaterSnapshot::Impl::updateControls(LLFloaterSnapshot* floater)
|
|||
floater->getChildView("send_btn")->setEnabled((shot_type == LLSnapshotLivePreview::SNAPSHOT_POSTCARD ||
|
||||
shot_type == LLSnapshotLivePreview::SNAPSHOT_WEB) &&
|
||||
got_snap && previewp->getDataSize() <= MAX_POSTCARD_DATASIZE);
|
||||
floater->getChildView("upload_btn")->setEnabled(shot_type == LLSnapshotLivePreview::SNAPSHOT_TEXTURE && got_snap);
|
||||
floater->getChildView("upload_btn")->setEnabled((shot_type == LLSnapshotLivePreview::SNAPSHOT_TEXTURE ||
|
||||
shot_type == LLSnapshotLivePreview::SNAPSHOT_FLICKR) && got_snap);
|
||||
floater->getChildView("save_btn")->setEnabled(shot_type == LLSnapshotLivePreview::SNAPSHOT_LOCAL && got_snap);
|
||||
|
||||
LLLocale locale(LLLocale::USER_LOCALE);
|
||||
|
|
@ -1419,7 +1452,6 @@ void LLFloaterSnapshot::Impl::updateControls(LLFloaterSnapshot* floater)
|
|||
S32 upload_cost = LLGlobalEconomy::Singleton::getInstance()->getPriceUpload();
|
||||
floater->childSetVisible("temp_check", is_advance && upload_cost > 0);
|
||||
floater->getChild<LLUICtrl>("texture")->setLabelArg("[AMOUNT]", llformat("%d",upload_cost));
|
||||
floater->getChild<LLUICtrl>("upload_btn")->setLabelArg("[AMOUNT]", llformat("%d",upload_cost));
|
||||
floater->getChild<LLUICtrl>("file_size_label")->setTextArg("[SIZE]", got_snap ? bytes_string : floater->getString("unknown"));
|
||||
floater->getChild<LLUICtrl>("file_size_label")->setColor(
|
||||
shot_type == LLSnapshotLivePreview::SNAPSHOT_POSTCARD
|
||||
|
|
@ -1447,6 +1479,7 @@ void LLFloaterSnapshot::Impl::updateControls(LLFloaterSnapshot* floater)
|
|||
}
|
||||
break;
|
||||
case LLSnapshotLivePreview::SNAPSHOT_LOCAL:
|
||||
case LLSnapshotLivePreview::SNAPSHOT_FLICKR:
|
||||
if(is_advance)
|
||||
{
|
||||
setResolution(floater, "local_size_combo");
|
||||
|
|
@ -1526,11 +1559,10 @@ void LLFloaterSnapshot::Impl::onClickKeep(void* data)
|
|||
{
|
||||
switch (previewp->getSnapshotType())
|
||||
{
|
||||
case LLSnapshotLivePreview::SNAPSHOT_WEB:
|
||||
previewp->saveWeb();
|
||||
break;
|
||||
|
||||
case LLSnapshotLivePreview::SNAPSHOT_POSTCARD:
|
||||
case LLSnapshotLivePreview::SNAPSHOT_WEB:
|
||||
previewp->saveWeb();
|
||||
break;
|
||||
case LLSnapshotLivePreview::SNAPSHOT_POSTCARD:
|
||||
{
|
||||
LLFloaterPostcard* floater = previewp->savePostcard();
|
||||
// if still in snapshot mode, put postcard floater in snapshot floaterview
|
||||
|
|
@ -1542,18 +1574,26 @@ void LLFloaterSnapshot::Impl::onClickKeep(void* data)
|
|||
view->addDependentFloater(floater, FALSE);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case LLSnapshotLivePreview::SNAPSHOT_TEXTURE:
|
||||
previewp->saveTexture();
|
||||
break;
|
||||
|
||||
case LLSnapshotLivePreview::SNAPSHOT_LOCAL:
|
||||
previewp->saveLocal();
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
break;
|
||||
case LLSnapshotLivePreview::SNAPSHOT_FLICKR:
|
||||
{
|
||||
KVFloaterFlickrUpload* floater = previewp->uploadToFlickr();
|
||||
if (floater && !gSavedSettings.getBOOL("CloseSnapshotOnKeep"))
|
||||
{
|
||||
gFloaterView->removeChild(floater);
|
||||
gSnapshotFloaterView->addChild(floater);
|
||||
view->addDependentFloater(floater, FALSE);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case LLSnapshotLivePreview::SNAPSHOT_TEXTURE:
|
||||
previewp->saveTexture();
|
||||
break;
|
||||
case LLSnapshotLivePreview::SNAPSHOT_LOCAL:
|
||||
previewp->saveLocal();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (gSavedSettings.getBOOL("CloseSnapshotOnKeep"))
|
||||
|
|
@ -1904,8 +1944,28 @@ void LLFloaterSnapshot::Impl::onCommitSnapshotType(LLUICtrl* ctrl, void* data)
|
|||
LLFloaterSnapshot *view = (LLFloaterSnapshot *)data;
|
||||
if (view)
|
||||
{
|
||||
gSavedSettings.setS32("LastSnapshotType", getTypeIndex(view));
|
||||
getPreviewView(view)->updateSnapshot(TRUE);
|
||||
int type = getTypeIndex(view);
|
||||
if(type == LLSnapshotLivePreview::SNAPSHOT_FLICKR && gSavedPerAccountSettings.getString("KittyFlickrToken") == "")
|
||||
{
|
||||
LLNotificationsUtil::add("KittyFlickrNeedAuth");
|
||||
KVFloaterFlickrAuth *floater = KVFloaterFlickrAuth::showFloater();
|
||||
// This makes sure we can still use the auth floater in freeze-frame mode by attaching it
|
||||
// to the snapshot floater.
|
||||
if(floater)
|
||||
{
|
||||
if(floater->getParent() == gFloaterView)
|
||||
{
|
||||
gFloaterView->removeChild(floater);
|
||||
gSnapshotFloaterView->addChild(floater);
|
||||
view->addDependentFloater(floater, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
gSavedSettings.setS32("LastSnapshotType", type);
|
||||
getPreviewView(view)->updateSnapshot(TRUE);
|
||||
}
|
||||
updateControls(view);
|
||||
}
|
||||
}
|
||||
|
|
@ -2139,9 +2199,17 @@ BOOL LLFloaterSnapshot::postBuild()
|
|||
{
|
||||
LLWebSharing::instance().init();
|
||||
}
|
||||
|
||||
if(gSavedSettings.getS32("LastSnapshotType") == LLSnapshotLivePreview::SNAPSHOT_FLICKR)
|
||||
{
|
||||
if(gSavedPerAccountSettings.getString("KittyFlickrToken") == "")
|
||||
{
|
||||
gSavedSettings.setS32("LastSnapshotType", LLSnapshotLivePreview::SNAPSHOT_LOCAL);
|
||||
}
|
||||
}
|
||||
|
||||
childSetCommitCallback("snapshot_type_radio", Impl::onCommitSnapshotType, this);
|
||||
childSetCommitCallback("local_format_combo", Impl::onCommitSnapshotFormat, this);
|
||||
childSetCommitCallback("format_combo", Impl::onCommitSnapshotFormat, this);
|
||||
|
||||
childSetAction("new_snapshot_btn", Impl::onClickNewSnapshot, this);
|
||||
|
||||
|
|
|
|||
|
|
@ -31,6 +31,8 @@
|
|||
|
||||
#include "llviewerfloaterreg.h"
|
||||
|
||||
#include "kvfloaterflickrauth.h"
|
||||
#include "kvfloaterflickrupload.h"
|
||||
#include "llcompilequeue.h"
|
||||
#include "llcallfloater.h"
|
||||
#include "llfloaterabout.h"
|
||||
|
|
@ -178,6 +180,8 @@ void LLViewerFloaterReg::registerFloaters()
|
|||
// [SL:KB] - Patch : UI-ProfileGroupFloater | Checked: 2010-09-08 (Catznip-2.1.2c) | Added: Catznip-2.1.2c
|
||||
LLFloaterReg::add("floater_profile_view", "floater_profile_view.xml",&LLFloaterReg::build<LLFloaterProfileView>);
|
||||
// [/SL:KB]
|
||||
LLFloaterReg::add("flickr_auth", "floater_flickr_auth.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<KVFloaterFlickrAuth>);
|
||||
LLFloaterReg::add("flickr_upload", "floater_flickr_upload.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<KVFloaterFlickrUpload>);
|
||||
LLFloaterReg::add("font_test", "floater_font_test.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterFontTest>);
|
||||
|
||||
LLFloaterReg::add("gestures", "floater_gesture.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterGesture>);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,23 @@
|
|||
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
|
||||
<floater
|
||||
can_resize="false"
|
||||
can_close="true"
|
||||
width="842"
|
||||
height="600"
|
||||
layout="topleft"
|
||||
name="floater_flickr_auth"
|
||||
help_topic="floater_flickr_auth"
|
||||
save_rect="true"
|
||||
single_instance="true"
|
||||
title="FLICKR AUTHENTICATION"
|
||||
>
|
||||
<web_browser
|
||||
follows="all"
|
||||
layout="topleft"
|
||||
left="5"
|
||||
right="-5"
|
||||
top="1"
|
||||
bottom="-5"
|
||||
ignore_ui_scale="true"
|
||||
name="browser"/>
|
||||
</floater>
|
||||
|
|
@ -0,0 +1,188 @@
|
|||
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
|
||||
<floater
|
||||
legacy_header_height="18"
|
||||
auto_tile="true"
|
||||
can_minimize="false"
|
||||
can_resize="false"
|
||||
height="330"
|
||||
layout="topleft"
|
||||
name="Uploadr"
|
||||
help_topic="flickr_uploader"
|
||||
title="UPLOAD TO FLICKR"
|
||||
width="450">
|
||||
<floater.string
|
||||
name="no_account">
|
||||
(not authorised)
|
||||
</floater.string>
|
||||
<floater.string
|
||||
name="uploading">
|
||||
Uploading to Flickr...
|
||||
</floater.string>
|
||||
<text
|
||||
type="string"
|
||||
length="1"
|
||||
bottom="35"
|
||||
follows="top|left"
|
||||
font="SansSerif"
|
||||
layout="topleft"
|
||||
left="12"
|
||||
name="title_label">
|
||||
Photo Title:
|
||||
</text>
|
||||
<line_editor
|
||||
follows="left|top"
|
||||
height="20"
|
||||
layout="topleft"
|
||||
left_delta="108"
|
||||
name="title_form"
|
||||
top_delta="-4"
|
||||
value="Snapshot"
|
||||
width="150" />
|
||||
<text
|
||||
type="string"
|
||||
length="1"
|
||||
bottom_delta="23"
|
||||
follows="top|left"
|
||||
font="SansSerif"
|
||||
layout="topleft"
|
||||
left="12"
|
||||
name="tags_label">
|
||||
Tags:
|
||||
</text>
|
||||
<line_editor
|
||||
follows="left|top"
|
||||
height="20"
|
||||
layout="topleft"
|
||||
left_delta="108"
|
||||
name="tags_form"
|
||||
top_delta="-4"
|
||||
width="150" />
|
||||
<text
|
||||
type="string"
|
||||
length="1"
|
||||
bottom_delta="23"
|
||||
follows="top|left"
|
||||
font="SansSerif"
|
||||
layout="topleft"
|
||||
left="12"
|
||||
name="maturity_label">
|
||||
Rating:
|
||||
</text>
|
||||
<icons_combo_box
|
||||
follows="left|top"
|
||||
height="20"
|
||||
label="Moderate"
|
||||
layout="topleft"
|
||||
left_delta="108"
|
||||
name="rating_combo"
|
||||
top_delta="-4"
|
||||
value="2"
|
||||
width="105">
|
||||
<icons_combo_box.drop_down_button
|
||||
image_overlay="Parcel_M_Light"
|
||||
image_overlay_alignment="left"
|
||||
imgoverlay_label_space="3"
|
||||
pad_left="3"/>
|
||||
<icons_combo_box.item
|
||||
label="Adult"
|
||||
name="Restricted"
|
||||
value="3">
|
||||
<item.columns
|
||||
halign="center"
|
||||
type="icon"
|
||||
value="Parcel_R_Light"
|
||||
width="20"/>
|
||||
</icons_combo_box.item>
|
||||
<icons_combo_box.item
|
||||
label="Moderate"
|
||||
name="Moderate"
|
||||
value="2">
|
||||
<item.columns
|
||||
halign="center"
|
||||
type="icon"
|
||||
value="Parcel_M_Light"
|
||||
width="20"/>
|
||||
</icons_combo_box.item>
|
||||
<icons_combo_box.item
|
||||
label="General"
|
||||
name="Safe"
|
||||
value="1">
|
||||
<item.columns
|
||||
halign="center"
|
||||
type="icon"
|
||||
value="Parcel_PG_Light"
|
||||
width="20"/>
|
||||
</icons_combo_box.item>
|
||||
</icons_combo_box>
|
||||
<text
|
||||
type="string"
|
||||
length="1"
|
||||
bottom_delta="23"
|
||||
follows="top|left"
|
||||
font="SansSerif"
|
||||
layout="topleft"
|
||||
left="12"
|
||||
name="account_label">
|
||||
Flickr Account:
|
||||
</text>
|
||||
<text
|
||||
follows="left|top"
|
||||
layout="topleft"
|
||||
font="SansSerif"
|
||||
left_delta="108"
|
||||
name="account_name">
|
||||
Loading...
|
||||
</text>
|
||||
<text
|
||||
type="string"
|
||||
length="1"
|
||||
bottom_delta="23"
|
||||
follows="top|left"
|
||||
font="SansSerif"
|
||||
layout="topleft"
|
||||
left="12"
|
||||
name="description_label">
|
||||
Description:
|
||||
</text>
|
||||
<text_editor
|
||||
type="string"
|
||||
length="1"
|
||||
follows="left|top|right|bottom"
|
||||
height="140"
|
||||
layout="topleft"
|
||||
left_delta="0"
|
||||
max_length="700"
|
||||
name="description_form"
|
||||
word_wrap="true"
|
||||
top_pad="10"
|
||||
width="427">
|
||||
</text_editor>
|
||||
<check_box
|
||||
name="show_position_check"
|
||||
height="15"
|
||||
value="true"
|
||||
layout="topleft"
|
||||
follows="left|bottom"
|
||||
left="10"
|
||||
top="307"
|
||||
label="Include location" />
|
||||
<button
|
||||
follows="right|bottom"
|
||||
height="23"
|
||||
label="Cancel"
|
||||
layout="topleft"
|
||||
name="cancel_btn"
|
||||
right="-10"
|
||||
top="300"
|
||||
width="100" />
|
||||
<button
|
||||
follows="right|bottom"
|
||||
height="23"
|
||||
label="Upload"
|
||||
layout="topleft"
|
||||
left_delta="-106"
|
||||
name="upload_btn"
|
||||
top_delta="0"
|
||||
enabled="false"
|
||||
width="100" />
|
||||
</floater>
|
||||
|
|
@ -50,6 +50,12 @@
|
|||
layout="topleft"
|
||||
name="local"
|
||||
top_pad="2" />
|
||||
<radio_item
|
||||
height="16"
|
||||
label="Upload to Flickr"
|
||||
layout="topleft"
|
||||
name="flickr"
|
||||
top_pad="2" />
|
||||
</radio_group>
|
||||
<ui_ctrl
|
||||
height="90"
|
||||
|
|
@ -95,7 +101,7 @@
|
|||
<button
|
||||
follows="left|top"
|
||||
height="23"
|
||||
label="Save (L$[AMOUNT])"
|
||||
label="Upload"
|
||||
layout="topleft"
|
||||
right="-5"
|
||||
name="upload_btn"
|
||||
|
|
@ -275,7 +281,7 @@
|
|||
label="Format"
|
||||
layout="topleft"
|
||||
left_pad="5"
|
||||
name="local_format_combo"
|
||||
name="format_combo"
|
||||
width="70">
|
||||
<combo_box.item
|
||||
label="PNG"
|
||||
|
|
@ -283,9 +289,12 @@
|
|||
<combo_box.item
|
||||
label="JPEG"
|
||||
name="JPEG" />
|
||||
<!--
|
||||
Disabled until someone convinces me that BMP support is actually useful.
|
||||
<combo_box.item
|
||||
label="BMP"
|
||||
name="BMP" />
|
||||
-->
|
||||
</combo_box>
|
||||
<spinner
|
||||
allow_text_entry="false"
|
||||
|
|
|
|||
|
|
@ -6900,6 +6900,67 @@ The site at '<nolink>[HOST_NAME]</nolink>' in realm '
|
|||
</form>
|
||||
</notification>
|
||||
|
||||
<notification
|
||||
icon="alertmodal.tga"
|
||||
name="KittyFlickrNeedAuth"
|
||||
type="alertmodal">
|
||||
You must authenticate [APP_NAME] before you can upload images to Flickr. Please login in and authorise [APP_NAME], then select "Upload to Flickr" again.
|
||||
|
||||
(If you have already authorised [APP_NAME] and are still logged in, this process may be automatic)
|
||||
</notification>
|
||||
|
||||
<notification
|
||||
icon="alertmodal.tga"
|
||||
name="KittyFlickrHTTPFail"
|
||||
type="alertmodal">
|
||||
Communication with Flickr failed. We don't know why.
|
||||
</notification>
|
||||
|
||||
<notification
|
||||
icon="alertmodal.tga"
|
||||
name="KittyFlickrTokenRejected"
|
||||
type="alertmodal">
|
||||
Flickr rejected your authentication token. This is probably because you revoked [APP_NAME]'s permissions. Please grant permission and try again.
|
||||
</notification>
|
||||
|
||||
<notification
|
||||
icon="alertmodal.tga"
|
||||
name="KittyFlickrGenericFail"
|
||||
type="alertmodal">
|
||||
Communication with Flickr failed ([CODE]):
|
||||
|
||||
[ERROR]
|
||||
</notification>
|
||||
|
||||
<notification
|
||||
icon="alertmodal.tga"
|
||||
name="KittyFlickrUploadCancelledAuthRejected"
|
||||
type="notifytip">
|
||||
The upload was cancelled because you did not grant [APP_NAME] permission to access your Flickr account.
|
||||
</notification>
|
||||
|
||||
<notification
|
||||
icon="alertmodal.tga"
|
||||
name="KittyFlickrUploadComplete"
|
||||
type="notifytip">
|
||||
[http://www.flickr.com/photos/upload/edit/?ids=[ID] [TITLE]] has been successfully uploaded to Flickr.
|
||||
</notification>
|
||||
|
||||
<notification
|
||||
icon="alertmodal.tga"
|
||||
name="KittyFlickrUploadFailed"
|
||||
type="alert">
|
||||
Failed to upload "[TITLE]" to Flickr (error [CODE]):
|
||||
|
||||
[ERROR]
|
||||
</notification>
|
||||
|
||||
<notification
|
||||
icon="alertmodal.tga"
|
||||
name="KittyFlickrUploadFailedNoError"
|
||||
type="alert">
|
||||
Failed dismally to upload "[TITLE]" to Flickr. Dunno why.
|
||||
</notification>
|
||||
|
||||
<global name="UnsupportedCPU">
|
||||
- Your CPU speed does not meet the minimum requirements.
|
||||
|
|
|
|||
Loading…
Reference in New Issue