summaryrefslogtreecommitdiff
path: root/indra/newview/llviewermenufile.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'indra/newview/llviewermenufile.cpp')
-rw-r--r--indra/newview/llviewermenufile.cpp2580
1 files changed, 1290 insertions, 1290 deletions
diff --git a/indra/newview/llviewermenufile.cpp b/indra/newview/llviewermenufile.cpp
index 5681047b89..bf618a765b 100644
--- a/indra/newview/llviewermenufile.cpp
+++ b/indra/newview/llviewermenufile.cpp
@@ -1,1290 +1,1290 @@
-/**
- * @file llviewermenufile.cpp
- * @brief "File" menu in the main menu bar.
- *
- * $LicenseInfo:firstyear=2002&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 "llviewermenufile.h"
-
-// project includes
-#include "llagent.h"
-#include "llagentbenefits.h"
-#include "llagentcamera.h"
-#include "llfilepicker.h"
-#include "llfloaterreg.h"
-#include "llbuycurrencyhtml.h"
-#include "llfloatermap.h"
-#include "llfloatermodelpreview.h"
-#include "llmaterialeditor.h"
-#include "llfloaterperms.h"
-#include "llfloatersnapshot.h"
-#include "llfloatersimplesnapshot.h"
-#include "llimage.h"
-#include "llimagebmp.h"
-#include "llimagepng.h"
-#include "llimagej2c.h"
-#include "llimagejpeg.h"
-#include "llimagetga.h"
-#include "llinventorymodel.h" // gInventory
-#include "llpluginclassmedia.h"
-#include "llresourcedata.h"
-#include "llstatusbar.h"
-#include "lltinygltfhelper.h"
-#include "lltoast.h"
-#include "llviewercontrol.h" // gSavedSettings
-#include "llviewertexturelist.h"
-#include "lluictrlfactory.h"
-#include "llviewerinventory.h"
-#include "llviewermenu.h" // gMenuHolder
-#include "llviewerparcelmgr.h"
-#include "llviewerregion.h"
-#include "llviewerstats.h"
-#include "llviewerwindow.h"
-#include "llappviewer.h"
-#include "lluploaddialog.h"
-#include "lltrans.h"
-#include "llfloaterbuycurrency.h"
-#include "llviewerassetupload.h"
-
-// linden libraries
-#include "llnotificationsutil.h"
-#include "llsdserialize.h"
-#include "llsdutil.h"
-#include "llstring.h"
-#include "lltransactiontypes.h"
-#include "lluuid.h"
-#include "llvorbisencode.h"
-#include "message.h"
-
-// system libraries
-#include <boost/tokenizer.hpp>
-
-class LLFileEnableUpload : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- return true;
- }
-};
-
-class LLFileEnableUploadModel : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- LLFloaterModelPreview* fmp = (LLFloaterModelPreview*) LLFloaterReg::findInstance("upload_model");
- if (fmp && fmp->isModelLoading())
- {
- return false;
- }
-
- return true;
- }
-};
-
-class LLFileEnableUploadMaterial : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- if (gAgent.getRegionCapability("UpdateMaterialAgentInventory").empty())
- {
- return false;
- }
-
- return true;
- }
-};
-
-class LLMeshEnabled : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- return gSavedSettings.getBOOL("MeshEnabled");
- }
-};
-
-class LLMeshUploadVisible : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- return gMeshRepo.meshUploadEnabled();
- }
-};
-
-LLMutex* LLFilePickerThread::sMutex = NULL;
-std::queue<LLFilePickerThread*> LLFilePickerThread::sDeadQ;
-
-void LLFilePickerThread::getFile()
-{
-#if LL_WINDOWS
- // Todo: get rid of LLFilePickerThread and make this modeless
- start();
-#elif LL_DARWIN
- runModeless();
-#else
- run();
-#endif
-}
-
-//virtual
-void LLFilePickerThread::run()
-{
-#if LL_WINDOWS
- bool blocking = false;
-#else
- bool blocking = true; // modal
-#endif
-
- LLFilePicker picker;
-
- if (mIsSaveDialog)
- {
- if (picker.getSaveFile(mSaveFilter, mProposedName, blocking))
- {
- mResponses.push_back(picker.getFirstFile());
- }
- }
- else
- {
- bool result = mIsGetMultiple ? picker.getMultipleOpenFiles(mLoadFilter, blocking) : picker.getOpenFile(mLoadFilter, blocking);
- if (result)
- {
- std::string filename = picker.getFirstFile(); // consider copying mFiles directly
- do
- {
- mResponses.push_back(filename);
- filename = picker.getNextFile();
- }
- while (mIsGetMultiple && !filename.empty());
- }
- }
-
- {
- LLMutexLock lock(sMutex);
- sDeadQ.push(this);
- }
-}
-
-void LLFilePickerThread::runModeless()
-{
- bool result = false;
- LLFilePicker picker;
-
- if (mIsSaveDialog)
- {
- result = picker.getSaveFileModeless(mSaveFilter,
- mProposedName,
- modelessStringCallback,
- this);
- }
- else if (mIsGetMultiple)
- {
- result = picker.getMultipleOpenFilesModeless(mLoadFilter, modelessVectorCallback, this);
- }
- else
- {
- result = picker.getOpenFileModeless(mLoadFilter, modelessVectorCallback, this);
- }
-
- if (!result)
- {
- LLMutexLock lock(sMutex);
- sDeadQ.push(this);
- }
-}
-
-void LLFilePickerThread::modelessStringCallback(bool success,
- std::string &response,
- void *user_data)
-{
- LLFilePickerThread *picker = (LLFilePickerThread*)user_data;
- if (success)
- {
- picker->mResponses.push_back(response);
- }
-
- {
- LLMutexLock lock(sMutex);
- sDeadQ.push(picker);
- }
-}
-
-void LLFilePickerThread::modelessVectorCallback(bool success,
- std::vector<std::string> &responses,
- void *user_data)
-{
- LLFilePickerThread *picker = (LLFilePickerThread*)user_data;
- if (success)
- {
- if (picker->mIsGetMultiple)
- {
- picker->mResponses = responses;
- }
- else
- {
- std::vector<std::string>::iterator iter = responses.begin();
- while (iter != responses.end())
- {
- if (!iter->empty())
- {
- picker->mResponses.push_back(*iter);
- break;
- }
- iter++;
- }
- }
- }
-
- {
- LLMutexLock lock(sMutex);
- sDeadQ.push(picker);
- }
-}
-
-//static
-void LLFilePickerThread::initClass()
-{
- sMutex = new LLMutex();
-}
-
-//static
-void LLFilePickerThread::cleanupClass()
-{
- clearDead();
-
- delete sMutex;
- sMutex = NULL;
-}
-
-//static
-void LLFilePickerThread::clearDead()
-{
- if (!sDeadQ.empty())
- {
- LLMutexLock lock(sMutex);
- while (!sDeadQ.empty())
- {
- LLFilePickerThread* thread = sDeadQ.front();
- thread->notify(thread->mResponses);
- delete thread;
- sDeadQ.pop();
- }
- }
-}
-
-LLFilePickerReplyThread::LLFilePickerReplyThread(const file_picked_signal_t::slot_type& cb, LLFilePicker::ELoadFilter filter, bool get_multiple, const file_picked_signal_t::slot_type& failure_cb)
- : LLFilePickerThread(filter, get_multiple),
- mLoadFilter(filter),
- mSaveFilter(LLFilePicker::FFSAVE_ALL),
- mFilePickedSignal(NULL),
- mFailureSignal(NULL)
-{
- mFilePickedSignal = new file_picked_signal_t();
- mFilePickedSignal->connect(cb);
-
- mFailureSignal = new file_picked_signal_t();
- mFailureSignal->connect(failure_cb);
-}
-
-LLFilePickerReplyThread::LLFilePickerReplyThread(const file_picked_signal_t::slot_type& cb, LLFilePicker::ESaveFilter filter, const std::string &proposed_name, const file_picked_signal_t::slot_type& failure_cb)
- : LLFilePickerThread(filter, proposed_name),
- mLoadFilter(LLFilePicker::FFLOAD_ALL),
- mSaveFilter(filter),
- mFilePickedSignal(NULL),
- mFailureSignal(NULL)
-{
- mFilePickedSignal = new file_picked_signal_t();
- mFilePickedSignal->connect(cb);
-
- mFailureSignal = new file_picked_signal_t();
- mFailureSignal->connect(failure_cb);
-}
-
-LLFilePickerReplyThread::~LLFilePickerReplyThread()
-{
- delete mFilePickedSignal;
- delete mFailureSignal;
-}
-
-void LLFilePickerReplyThread::startPicker(const file_picked_signal_t::slot_type & cb, LLFilePicker::ELoadFilter filter, bool get_multiple, const file_picked_signal_t::slot_type & failure_cb)
-{
- (new LLFilePickerReplyThread(cb, filter, get_multiple, failure_cb))->getFile();
-}
-
-void LLFilePickerReplyThread::startPicker(const file_picked_signal_t::slot_type & cb, LLFilePicker::ESaveFilter filter, const std::string & proposed_name, const file_picked_signal_t::slot_type & failure_cb)
-{
- (new LLFilePickerReplyThread(cb, filter, proposed_name, failure_cb))->getFile();
-}
-
-void LLFilePickerReplyThread::notify(const std::vector<std::string>& filenames)
-{
- if (filenames.empty())
- {
- if (mFailureSignal)
- {
- (*mFailureSignal)(filenames, mLoadFilter, mSaveFilter);
- }
- }
- else
- {
- if (mFilePickedSignal)
- {
- (*mFilePickedSignal)(filenames, mLoadFilter, mSaveFilter);
- }
- }
-}
-
-
-LLMediaFilePicker::LLMediaFilePicker(LLPluginClassMedia* plugin, LLFilePicker::ELoadFilter filter, bool get_multiple)
- : LLFilePickerThread(filter, get_multiple),
- mPlugin(plugin->getSharedPtr())
-{
-}
-
-LLMediaFilePicker::LLMediaFilePicker(LLPluginClassMedia* plugin, LLFilePicker::ESaveFilter filter, const std::string &proposed_name)
- : LLFilePickerThread(filter, proposed_name),
- mPlugin(plugin->getSharedPtr())
-{
-}
-
-void LLMediaFilePicker::notify(const std::vector<std::string>& filenames)
-{
- mPlugin->sendPickFileResponse(mResponses);
- mPlugin = NULL;
-}
-
-//============================================================================
-
-#if LL_WINDOWS
-static std::string SOUND_EXTENSIONS = "wav";
-static std::string IMAGE_EXTENSIONS = "tga bmp jpg jpeg png";
-static std::string ANIM_EXTENSIONS = "bvh anim";
-static std::string XML_EXTENSIONS = "xml";
-static std::string SLOBJECT_EXTENSIONS = "slobject";
-#endif
-static std::string ALL_FILE_EXTENSIONS = "*.*";
-static std::string MODEL_EXTENSIONS = "dae";
-static std::string MATERIAL_EXTENSIONS = "gltf glb";
-
-std::string build_extensions_string(LLFilePicker::ELoadFilter filter)
-{
- switch(filter)
- {
-#if LL_WINDOWS
- case LLFilePicker::FFLOAD_IMAGE:
- return IMAGE_EXTENSIONS;
- case LLFilePicker::FFLOAD_WAV:
- return SOUND_EXTENSIONS;
- case LLFilePicker::FFLOAD_ANIM:
- return ANIM_EXTENSIONS;
- case LLFilePicker::FFLOAD_SLOBJECT:
- return SLOBJECT_EXTENSIONS;
- case LLFilePicker::FFLOAD_MODEL:
- return MODEL_EXTENSIONS;
- case LLFilePicker::FFLOAD_MATERIAL:
- return MATERIAL_EXTENSIONS;
- case LLFilePicker::FFLOAD_XML:
- return XML_EXTENSIONS;
- case LLFilePicker::FFLOAD_ALL:
- case LLFilePicker::FFLOAD_EXE:
- return ALL_FILE_EXTENSIONS;
-#endif
- default:
- return ALL_FILE_EXTENSIONS;
- }
-}
-
-
-const bool check_file_extension(const std::string& filename, LLFilePicker::ELoadFilter type)
-{
- std::string ext = gDirUtilp->getExtension(filename);
-
- //strincmp doesn't like NULL pointers
- if (ext.empty())
- {
- std::string short_name = gDirUtilp->getBaseFileName(filename);
-
- // No extension
- LLSD args;
- args["FILE"] = short_name;
- LLNotificationsUtil::add("NoFileExtension", args);
- return false;
- }
- else
- {
- //so there is an extension
- //loop over the valid extensions and compare to see
- //if the extension is valid
-
- //now grab the set of valid file extensions
- std::string valid_extensions = build_extensions_string(type);
-
- bool ext_valid = false;
-
- typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
- boost::char_separator<char> sep(" ");
- tokenizer tokens(valid_extensions, sep);
- tokenizer::iterator token_iter;
-
- //now loop over all valid file extensions
- //and compare them to the extension of the file
- //to be uploaded
- for (token_iter = tokens.begin();
- token_iter != tokens.end() && !ext_valid;
- ++token_iter)
- {
- const std::string& cur_token = *token_iter;
-
- if (cur_token == ext || cur_token == "*.*")
- {
- //valid extension
- //or the acceptable extension is any
- ext_valid = true;
- }
- }//end for (loop over all tokens)
-
- if (!ext_valid)
- {
- //should only get here if the extension exists
- //but is invalid
- LLSD args;
- args["EXTENSION"] = ext;
- args["VALIDS"] = valid_extensions;
- LLNotificationsUtil::add("InvalidFileExtension", args);
- return false;
- }
- }//end else (non-null extension)
- return true;
-}
-
-const void upload_single_file(const std::vector<std::string>& filenames, LLFilePicker::ELoadFilter type)
-{
- std::string filename = filenames[0];
- if (!check_file_extension(filename, type)) return;
-
- if (!filename.empty())
- {
- if (type == LLFilePicker::FFLOAD_WAV)
- {
- // pre-qualify wavs to make sure the format is acceptable
- std::string error_msg;
- if (check_for_invalid_wav_formats(filename, error_msg))
- {
- LL_INFOS() << error_msg << ": " << filename << LL_ENDL;
- LLSD args;
- args["FILE"] = filename;
- LLNotificationsUtil::add(error_msg, args);
- return;
- }
- else
- {
- LLFloaterReg::showInstance("upload_sound", LLSD(filename));
- }
- }
- if (type == LLFilePicker::FFLOAD_IMAGE)
- {
- LLFloaterReg::showInstance("upload_image", LLSD(filename));
- }
- if (type == LLFilePicker::FFLOAD_ANIM)
- {
- std::string filename_lc(filename);
- LLStringUtil::toLower(filename_lc);
- if (filename_lc.rfind(".anim") != std::string::npos)
- {
- LLFloaterReg::showInstance("upload_anim_anim", LLSD(filename));
- }
- else
- {
- LLFloaterReg::showInstance("upload_anim_bvh", LLSD(filename));
- }
- }
- }
- return;
-}
-
-void do_bulk_upload(std::vector<std::string> filenames, const LLSD& notification, const LLSD& response)
-{
- S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
- if (option != 0)
- {
- // Cancel upload
- return;
- }
-
- for (std::vector<std::string>::const_iterator in_iter = filenames.begin(); in_iter != filenames.end(); ++in_iter)
- {
- std::string filename = (*in_iter);
-
- std::string name = gDirUtilp->getBaseFileName(filename, true);
- std::string asset_name = name;
- LLStringUtil::replaceNonstandardASCII(asset_name, '?');
- LLStringUtil::replaceChar(asset_name, '|', '?');
- LLStringUtil::stripNonprintable(asset_name);
- LLStringUtil::trim(asset_name);
-
- std::string ext = gDirUtilp->getExtension(filename);
- LLAssetType::EType asset_type;
- U32 codec;
- S32 expected_upload_cost;
- if (LLResourceUploadInfo::findAssetTypeAndCodecOfExtension(ext, asset_type, codec) &&
- LLAgentBenefitsMgr::current().findUploadCost(asset_type, expected_upload_cost))
- {
- LLResourceUploadInfo::ptr_t uploadInfo(new LLNewFileResourceUploadInfo(
- filename,
- asset_name,
- asset_name, 0,
- LLFolderType::FT_NONE, LLInventoryType::IT_NONE,
- LLFloaterPerms::getNextOwnerPerms("Uploads"),
- LLFloaterPerms::getGroupPerms("Uploads"),
- LLFloaterPerms::getEveryonePerms("Uploads"),
- expected_upload_cost));
-
- upload_new_resource(uploadInfo);
- }
-
- // gltf does not use normal upload procedure
- if (ext == "gltf" || ext == "glb")
- {
- tinygltf::Model model;
- if (LLTinyGLTFHelper::loadModel(filename, model))
- {
- S32 materials_in_file = model.materials.size();
-
- for (S32 i = 0; i < materials_in_file; i++)
- {
- // Todo:
- // 1. Decouple bulk upload from material editor
- // 2. Take into account possiblity of identical textures
- LLMaterialEditor::uploadMaterialFromModel(filename, model, i);
- }
- }
- }
- }
-}
-
-bool get_bulk_upload_expected_cost(const std::vector<std::string>& filenames, S32& total_cost, S32& file_count, S32& bvh_count)
-{
- total_cost = 0;
- file_count = 0;
- bvh_count = 0;
- for (std::vector<std::string>::const_iterator in_iter = filenames.begin(); in_iter != filenames.end(); ++in_iter)
- {
- std::string filename = (*in_iter);
- std::string ext = gDirUtilp->getExtension(filename);
-
- if (ext == "bvh")
- {
- bvh_count++;
- }
-
- LLAssetType::EType asset_type;
- U32 codec;
- S32 cost;
-
- if (LLResourceUploadInfo::findAssetTypeAndCodecOfExtension(ext, asset_type, codec) &&
- LLAgentBenefitsMgr::current().findUploadCost(asset_type, cost))
- {
- total_cost += cost;
- file_count++;
- }
-
- if (ext == "gltf" || ext == "glb")
- {
- S32 texture_upload_cost = LLAgentBenefitsMgr::current().getTextureUploadCost();
-
- tinygltf::Model model;
-
- if (LLTinyGLTFHelper::loadModel(filename, model))
- {
- S32 materials_in_file = model.materials.size();
-
- for (S32 i = 0; i < materials_in_file; i++)
- {
- LLPointer<LLFetchedGLTFMaterial> material = new LLFetchedGLTFMaterial();
- std::string material_name;
- bool decode_successful = LLTinyGLTFHelper::getMaterialFromModel(filename, model, i, material.get(), material_name);
-
- if (decode_successful)
- {
- // Todo: make it account for possibility of same texture in different
- // materials and even in scope of same material
- S32 texture_count = 0;
- if (material->mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_BASE_COLOR].notNull())
- {
- texture_count++;
- }
- if (material->mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_METALLIC_ROUGHNESS].notNull())
- {
- texture_count++;
- }
- if (material->mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_NORMAL].notNull())
- {
- texture_count++;
- }
- if (material->mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_EMISSIVE].notNull())
- {
- texture_count++;
- }
- total_cost += texture_count * texture_upload_cost;
- file_count++;
- }
- }
- }
- }
- }
-
- return file_count > 0;
-}
-
-const void upload_bulk(const std::vector<std::string>& filenames, LLFilePicker::ELoadFilter type)
-{
- // TODO:
- // Check user balance for entire cost
- // Charge user entire cost
- // Loop, uploading
- // If an upload fails, refund the user for that one
- //
- // Also fix single upload to charge first, then refund
-
- // FIXME PREMIUM what about known types that can't be bulk uploaded
- // (bvh)? These will fail in the item by item upload but won't be
- // mentioned in the notification.
- std::vector<std::string> filtered_filenames;
- for (std::vector<std::string>::const_iterator in_iter = filenames.begin(); in_iter != filenames.end(); ++in_iter)
- {
- const std::string& filename = *in_iter;
- if (check_file_extension(filename, type))
- {
- filtered_filenames.push_back(filename);
- }
- }
-
- S32 expected_upload_cost;
- S32 expected_upload_count;
- S32 bvh_count;
- if (get_bulk_upload_expected_cost(filtered_filenames, expected_upload_cost, expected_upload_count, bvh_count))
- {
- LLSD args;
- args["COST"] = expected_upload_cost;
- args["COUNT"] = expected_upload_count;
- LLNotificationsUtil::add("BulkUploadCostConfirmation", args, LLSD(), boost::bind(do_bulk_upload, filtered_filenames, _1, _2));
-
- if (filtered_filenames.size() > expected_upload_count)
- {
- if (bvh_count == filtered_filenames.size() - expected_upload_count)
- {
- LLNotificationsUtil::add("DoNotSupportBulkAnimationUpload");
- }
- else
- {
- LLNotificationsUtil::add("BulkUploadIncompatibleFiles");
- }
- }
- }
- else if (bvh_count == filtered_filenames.size())
- {
- LLNotificationsUtil::add("DoNotSupportBulkAnimationUpload");
- }
- else
- {
- LLNotificationsUtil::add("BulkUploadNoCompatibleFiles");
- }
-
-}
-
-class LLFileUploadImage : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- if (gAgentCamera.cameraMouselook())
- {
- gAgentCamera.changeCameraToDefault();
- }
- LLFilePickerReplyThread::startPicker(boost::bind(&upload_single_file, _1, _2), LLFilePicker::FFLOAD_IMAGE, false);
- return true;
- }
-};
-
-class LLFileUploadModel : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- LLFloaterModelPreview::showModelPreview();
- return true;
- }
-};
-
-class LLFileUploadMaterial : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- LLMaterialEditor::importMaterial();
- return true;
- }
-};
-
-class LLFileUploadSound : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- if (gAgentCamera.cameraMouselook())
- {
- gAgentCamera.changeCameraToDefault();
- }
- LLFilePickerReplyThread::startPicker(boost::bind(&upload_single_file, _1, _2), LLFilePicker::FFLOAD_WAV, false);
- return true;
- }
-};
-
-class LLFileUploadAnim : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- if (gAgentCamera.cameraMouselook())
- {
- gAgentCamera.changeCameraToDefault();
- }
- LLFilePickerReplyThread::startPicker(boost::bind(&upload_single_file, _1, _2), LLFilePicker::FFLOAD_ANIM, false);
- return true;
- }
-};
-
-class LLFileUploadBulk : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- if (gAgentCamera.cameraMouselook())
- {
- gAgentCamera.changeCameraToDefault();
- }
- LLFilePickerReplyThread::startPicker(boost::bind(&upload_bulk, _1, _2), LLFilePicker::FFLOAD_ALL, true);
- return true;
- }
-};
-
-void upload_error(const std::string& error_message, const std::string& label, const std::string& filename, const LLSD& args)
-{
- LL_WARNS() << error_message << LL_ENDL;
- LLNotificationsUtil::add(label, args);
- if(LLFile::remove(filename) == -1)
- {
- LL_DEBUGS() << "unable to remove temp file" << LL_ENDL;
- }
- LLFilePicker::instance().reset();
-}
-
-class LLFileEnableCloseWindow : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- bool frontmost_fl_exists = (NULL != gFloaterView->getFrontmostClosableFloater());
- bool frontmost_snapshot_fl_exists = (NULL != gSnapshotFloaterView->getFrontmostClosableFloater());
-
- return !LLNotificationsUI::LLToast::isAlertToastShown() && (frontmost_fl_exists || frontmost_snapshot_fl_exists);
- }
-};
-
-class LLFileCloseWindow : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- bool frontmost_fl_exists = (NULL != gFloaterView->getFrontmostClosableFloater());
- LLFloater* snapshot_floater = gSnapshotFloaterView->getFrontmostClosableFloater();
-
- if(snapshot_floater && (!frontmost_fl_exists || snapshot_floater->hasFocus()))
- {
- snapshot_floater->closeFloater();
- if (gFocusMgr.getKeyboardFocus() == NULL)
- {
- gFloaterView->focusFrontFloater();
- }
- }
- else
- {
- LLFloater::closeFrontmostFloater();
- }
- if (gMenuHolder) gMenuHolder->hideMenus();
- return true;
- }
-};
-
-class LLFileEnableCloseAllWindows : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- LLFloaterSnapshot* floater_snapshot = LLFloaterSnapshot::findInstance();
- bool is_floaters_snapshot_opened = (floater_snapshot && floater_snapshot->isInVisibleChain());
- bool open_children = gFloaterView->allChildrenClosed() && !is_floaters_snapshot_opened;
- return !open_children && !LLNotificationsUI::LLToast::isAlertToastShown();
- }
-};
-
-class LLFileCloseAllWindows : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- bool app_quitting = false;
- gFloaterView->closeAllChildren(app_quitting);
- LLFloaterSnapshot* floater_snapshot = LLFloaterSnapshot::findInstance();
- if (floater_snapshot)
- floater_snapshot->closeFloater(app_quitting);
- if (gMenuHolder) gMenuHolder->hideMenus();
- return true;
- }
-};
-
-class LLFileTakeSnapshotToDisk : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- LLPointer<LLImageRaw> raw = new LLImageRaw;
-
- S32 width = gViewerWindow->getWindowWidthRaw();
- S32 height = gViewerWindow->getWindowHeightRaw();
-
- bool render_ui = gSavedSettings.getBOOL("RenderUIInSnapshot");
- bool render_hud = gSavedSettings.getBOOL("RenderHUDInSnapshot");
- bool render_no_post = gSavedSettings.getBOOL("RenderSnapshotNoPost");
-
- bool high_res = gSavedSettings.getBOOL("HighResSnapshot");
- if (high_res)
- {
- width *= 2;
- height *= 2;
- // not compatible with UI/HUD
- render_ui = false;
- render_hud = false;
- }
-
- if (gViewerWindow->rawSnapshot(raw,
- width,
- height,
- true,
- false,
- render_ui,
- render_hud,
- false,
- render_no_post,
- LLSnapshotModel::SNAPSHOT_TYPE_COLOR,
- high_res ? S32_MAX : MAX_SNAPSHOT_IMAGE_SIZE)) //per side
- {
- LLPointer<LLImageFormatted> formatted;
- LLSnapshotModel::ESnapshotFormat fmt = (LLSnapshotModel::ESnapshotFormat) gSavedSettings.getS32("SnapshotFormat");
- switch (fmt)
- {
- case LLSnapshotModel::SNAPSHOT_FORMAT_JPEG:
- formatted = new LLImageJPEG(gSavedSettings.getS32("SnapshotQuality"));
- break;
- default:
- LL_WARNS() << "Unknown local snapshot format: " << fmt << LL_ENDL;
- case LLSnapshotModel::SNAPSHOT_FORMAT_PNG:
- formatted = new LLImagePNG;
- break;
- case LLSnapshotModel::SNAPSHOT_FORMAT_BMP:
- formatted = new LLImageBMP;
- break;
- }
- formatted->enableOverSize() ;
- formatted->encode(raw, 0);
- formatted->disableOverSize() ;
- LLSnapshotLivePreview::saveLocal(formatted);
- }
- return true;
- }
-};
-
-class LLFileQuit : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- LLAppViewer::instance()->userQuit();
- return true;
- }
-};
-
-
-void handle_compress_image(void*)
-{
- LLFilePicker& picker = LLFilePicker::instance();
- if (picker.getMultipleOpenFiles(LLFilePicker::FFLOAD_IMAGE))
- {
- std::string infile = picker.getFirstFile();
- while (!infile.empty())
- {
- std::string outfile = infile + ".j2c";
-
- LL_INFOS() << "Input: " << infile << LL_ENDL;
- LL_INFOS() << "Output: " << outfile << LL_ENDL;
-
- bool success;
-
- success = LLViewerTextureList::createUploadFile(infile, outfile, IMG_CODEC_TGA);
-
- if (success)
- {
- LL_INFOS() << "Compression complete" << LL_ENDL;
- }
- else
- {
- LL_INFOS() << "Compression failed: " << LLImage::getLastError() << LL_ENDL;
- }
-
- infile = picker.getNextFile();
- }
- }
-}
-
-// No convinient check in LLFile, and correct way would be something
-// like GetFileSizeEx, which is too OS specific for current purpose
-// so doing dirty, but OS independent fopen and fseek
-size_t get_file_size(std::string &filename)
-{
- LLFILE* file = LLFile::fopen(filename, "rb"); /*Flawfinder: ignore*/
- if (!file)
- {
- LL_WARNS() << "Error opening " << filename << LL_ENDL;
- return 0;
- }
-
- // read in the whole file
- fseek(file, 0L, SEEK_END);
- size_t file_length = (size_t)ftell(file);
- fclose(file);
- return file_length;
-}
-
-void handle_compress_file_test(void*)
-{
- LLFilePicker& picker = LLFilePicker::instance();
- if (picker.getOpenFile())
- {
- std::string infile = picker.getFirstFile();
- if (!infile.empty())
- {
- std::string packfile = infile + ".pack_test";
- std::string unpackfile = infile + ".unpack_test";
-
- S64Bytes initial_size = S64Bytes(get_file_size(infile));
-
- bool success;
-
- F64 total_seconds = LLTimer::getTotalSeconds();
- success = gzip_file(infile, packfile);
- F64 result_pack_seconds = LLTimer::getTotalSeconds() - total_seconds;
-
- if (success)
- {
- S64Bytes packed_size = S64Bytes(get_file_size(packfile));
-
- LL_INFOS() << "Packing complete, time: " << result_pack_seconds << " size: " << packed_size << LL_ENDL;
- total_seconds = LLTimer::getTotalSeconds();
- success = gunzip_file(packfile, unpackfile);
- F64 result_unpack_seconds = LLTimer::getTotalSeconds() - total_seconds;
-
- if (success)
- {
- S64Bytes unpacked_size = S64Bytes(get_file_size(unpackfile));
-
- LL_INFOS() << "Unpacking complete, time: " << result_unpack_seconds << " size: " << unpacked_size << LL_ENDL;
-
- LLSD args;
- args["FILE"] = infile;
- args["PACK_TIME"] = result_pack_seconds;
- args["UNPACK_TIME"] = result_unpack_seconds;
- args["SIZE"] = LLSD::Integer(initial_size.valueInUnits<LLUnits::Kilobytes>());
- args["PSIZE"] = LLSD::Integer(packed_size.valueInUnits<LLUnits::Kilobytes>());
- args["USIZE"] = LLSD::Integer(unpacked_size.valueInUnits<LLUnits::Kilobytes>());
- LLNotificationsUtil::add("CompressionTestResults", args);
-
- LLFile::remove(packfile);
- LLFile::remove(unpackfile);
- }
- else
- {
- LL_INFOS() << "Failed to uncompress file: " << packfile << LL_ENDL;
- LLFile::remove(packfile);
- }
-
- }
- else
- {
- LL_INFOS() << "Failed to compres file: " << infile << LL_ENDL;
- }
- }
- else
- {
- LL_INFOS() << "Failed to open file" << LL_ENDL;
- }
- }
- else
- {
- LL_INFOS() << "Failed to open file" << LL_ENDL;
- }
-}
-
-
-LLUUID upload_new_resource(
- const std::string& src_filename,
- std::string name,
- std::string desc,
- S32 compression_info,
- LLFolderType::EType destination_folder_type,
- LLInventoryType::EType inv_type,
- U32 next_owner_perms,
- U32 group_perms,
- U32 everyone_perms,
- const std::string& display_name,
- LLAssetStorage::LLStoreAssetCallback callback,
- S32 expected_upload_cost,
- void *userdata,
- bool show_inventory)
-{
-
- LLResourceUploadInfo::ptr_t uploadInfo(std::make_shared<LLNewFileResourceUploadInfo>(
- src_filename,
- name, desc, compression_info,
- destination_folder_type, inv_type,
- next_owner_perms, group_perms, everyone_perms,
- expected_upload_cost, show_inventory));
- upload_new_resource(uploadInfo, callback, userdata);
-
- return LLUUID::null;
-}
-
-void upload_done_callback(
- const LLUUID& uuid,
- void* user_data,
- S32 result,
- LLExtStat ext_status) // StoreAssetData callback (fixed)
-{
- LLResourceData* data = (LLResourceData*)user_data;
- S32 expected_upload_cost = data ? data->mExpectedUploadCost : 0;
- //LLAssetType::EType pref_loc = data->mPreferredLocation;
- bool is_balance_sufficient = true;
-
- if(data)
- {
- if (result >= 0)
- {
- LLFolderType::EType dest_loc = (data->mPreferredLocation == LLFolderType::FT_NONE) ? LLFolderType::assetTypeToFolderType(data->mAssetInfo.mType) : data->mPreferredLocation;
-
- if (LLAssetType::AT_SOUND == data->mAssetInfo.mType ||
- LLAssetType::AT_TEXTURE == data->mAssetInfo.mType ||
- LLAssetType::AT_ANIMATION == data->mAssetInfo.mType)
- {
- // Charge the user for the upload.
- LLViewerRegion* region = gAgent.getRegion();
-
- if(!(can_afford_transaction(expected_upload_cost)))
- {
- LLBuyCurrencyHTML::openCurrencyFloater( "", expected_upload_cost );
- is_balance_sufficient = false;
- }
- else if(region)
- {
- // Charge user for upload
- gStatusBar->debitBalance(expected_upload_cost);
-
- LLMessageSystem* msg = gMessageSystem;
- msg->newMessageFast(_PREHASH_MoneyTransferRequest);
- msg->nextBlockFast(_PREHASH_AgentData);
- msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
- msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
- msg->nextBlockFast(_PREHASH_MoneyData);
- msg->addUUIDFast(_PREHASH_SourceID, gAgent.getID());
- msg->addUUIDFast(_PREHASH_DestID, LLUUID::null);
- msg->addU8("Flags", 0);
- // we tell the sim how much we were expecting to pay so it
- // can respond to any discrepancy
- msg->addS32Fast(_PREHASH_Amount, expected_upload_cost);
- msg->addU8Fast(_PREHASH_AggregatePermNextOwner, (U8)LLAggregatePermissions::AP_EMPTY);
- msg->addU8Fast(_PREHASH_AggregatePermInventory, (U8)LLAggregatePermissions::AP_EMPTY);
- msg->addS32Fast(_PREHASH_TransactionType, TRANS_UPLOAD_CHARGE);
- msg->addStringFast(_PREHASH_Description, NULL);
- msg->sendReliable(region->getHost());
- }
- }
-
- if(is_balance_sufficient)
- {
- // Actually add the upload to inventory
- LL_INFOS() << "Adding " << uuid << " to inventory." << LL_ENDL;
- const LLUUID folder_id = gInventory.findCategoryUUIDForType(dest_loc);
- if(folder_id.notNull())
- {
- U32 next_owner_perms = data->mNextOwnerPerm;
- if(PERM_NONE == next_owner_perms)
- {
- next_owner_perms = PERM_MOVE | PERM_TRANSFER;
- }
- create_inventory_item(gAgent.getID(), gAgent.getSessionID(),
- folder_id, data->mAssetInfo.mTransactionID, data->mAssetInfo.getName(),
- data->mAssetInfo.getDescription(), data->mAssetInfo.mType,
- data->mInventoryType, NO_INV_SUBTYPE, next_owner_perms,
- LLPointer<LLInventoryCallback>(NULL));
- }
- else
- {
- LL_WARNS() << "Can't find a folder to put it in" << LL_ENDL;
- }
- }
- }
- else // if(result >= 0)
- {
- LLSD args;
- args["FILE"] = LLInventoryType::lookupHumanReadable(data->mInventoryType);
- args["REASON"] = std::string(LLAssetStorage::getErrorString(result));
- LLNotificationsUtil::add("CannotUploadReason", args);
- }
-
- delete data;
- data = NULL;
- }
-
- LLUploadDialog::modalUploadFinished();
-
- // *NOTE: This is a pretty big hack. What this does is check the
- // file picker if there are any more pending uploads. If so,
- // upload that file.
- const std::string& next_file = LLFilePicker::instance().getNextFile();
- if(is_balance_sufficient && !next_file.empty())
- {
- std::string asset_name = gDirUtilp->getBaseFileName(next_file, true);
- LLStringUtil::replaceNonstandardASCII( asset_name, '?' );
- LLStringUtil::replaceChar(asset_name, '|', '?');
- LLStringUtil::stripNonprintable(asset_name);
- LLStringUtil::trim(asset_name);
-
- std::string display_name = LLStringUtil::null;
- LLAssetStorage::LLStoreAssetCallback callback;
- void *userdata = NULL;
- upload_new_resource(
- next_file,
- asset_name,
- asset_name, // file
- 0,
- LLFolderType::FT_NONE,
- LLInventoryType::IT_NONE,
- LLFloaterPerms::getNextOwnerPerms("Uploads"),
- LLFloaterPerms::getGroupPerms("Uploads"),
- LLFloaterPerms::getEveryonePerms("Uploads"),
- display_name,
- callback,
- expected_upload_cost, // assuming next in a group of uploads is of roughly the same type, i.e. same upload cost
- userdata);
- }
-}
-
-void upload_new_resource(
- LLResourceUploadInfo::ptr_t &uploadInfo,
- LLAssetStorage::LLStoreAssetCallback callback,
- void *userdata)
-{
- if(gDisconnected)
- {
- return ;
- }
-
-// uploadInfo->setAssetType(assetType);
-// uploadInfo->setTransactionId(tid);
-
-
- std::string url = gAgent.getRegionCapability("NewFileAgentInventory");
-
- if ( !url.empty() )
- {
- LLViewerAssetUpload::EnqueueInventoryUpload(url, uploadInfo);
- }
- else
- {
- uploadInfo->prepareUpload();
- uploadInfo->logPreparedUpload();
-
- LL_INFOS() << "NewAgentInventory capability not found, new agent inventory via asset system." << LL_ENDL;
- // check for adequate funds
- // TODO: do this check on the sim
- if (LLAssetType::AT_SOUND == uploadInfo->getAssetType() ||
- LLAssetType::AT_TEXTURE == uploadInfo->getAssetType() ||
- LLAssetType::AT_ANIMATION == uploadInfo->getAssetType())
- {
- S32 balance = gStatusBar->getBalance();
- if (balance < uploadInfo->getExpectedUploadCost())
- {
- // insufficient funds, bail on this upload
- LLBuyCurrencyHTML::openCurrencyFloater("", uploadInfo->getExpectedUploadCost());
- return;
- }
- }
-
- LLResourceData* data = new LLResourceData;
- data->mAssetInfo.mTransactionID = uploadInfo->getTransactionId();
- data->mAssetInfo.mUuid = uploadInfo->getAssetId();
- data->mAssetInfo.mType = uploadInfo->getAssetType();
- data->mAssetInfo.mCreatorID = gAgentID;
- data->mInventoryType = uploadInfo->getInventoryType();
- data->mNextOwnerPerm = uploadInfo->getNextOwnerPerms();
- data->mExpectedUploadCost = uploadInfo->getExpectedUploadCost();
- data->mUserData = userdata;
- data->mAssetInfo.setName(uploadInfo->getName());
- data->mAssetInfo.setDescription(uploadInfo->getDescription());
- data->mPreferredLocation = uploadInfo->getDestinationFolderType();
-
- LLAssetStorage::LLStoreAssetCallback asset_callback = &upload_done_callback;
- if (callback)
- {
- asset_callback = callback;
- }
- gAssetStorage->storeAssetData(
- data->mAssetInfo.mTransactionID,
- data->mAssetInfo.mType,
- asset_callback,
- (void*)data,
- false);
- }
-}
-
-
-void init_menu_file()
-{
- view_listener_t::addCommit(new LLFileUploadImage(), "File.UploadImage");
- view_listener_t::addCommit(new LLFileUploadSound(), "File.UploadSound");
- view_listener_t::addCommit(new LLFileUploadAnim(), "File.UploadAnim");
- view_listener_t::addCommit(new LLFileUploadModel(), "File.UploadModel");
- view_listener_t::addCommit(new LLFileUploadMaterial(), "File.UploadMaterial");
- view_listener_t::addCommit(new LLFileUploadBulk(), "File.UploadBulk");
- view_listener_t::addCommit(new LLFileCloseWindow(), "File.CloseWindow");
- view_listener_t::addCommit(new LLFileCloseAllWindows(), "File.CloseAllWindows");
- view_listener_t::addEnable(new LLFileEnableCloseWindow(), "File.EnableCloseWindow");
- view_listener_t::addEnable(new LLFileEnableCloseAllWindows(), "File.EnableCloseAllWindows");
- view_listener_t::addCommit(new LLFileTakeSnapshotToDisk(), "File.TakeSnapshotToDisk");
- view_listener_t::addCommit(new LLFileQuit(), "File.Quit");
-
- view_listener_t::addEnable(new LLFileEnableUpload(), "File.EnableUpload");
- view_listener_t::addEnable(new LLFileEnableUploadModel(), "File.EnableUploadModel");
- view_listener_t::addEnable(new LLFileEnableUploadMaterial(), "File.EnableUploadMaterial");
- view_listener_t::addMenu(new LLMeshEnabled(), "File.MeshEnabled");
- view_listener_t::addMenu(new LLMeshUploadVisible(), "File.VisibleUploadModel");
-
- // "File.SaveTexture" moved to llpanelmaininventory so that it can be properly handled.
-}
+/**
+ * @file llviewermenufile.cpp
+ * @brief "File" menu in the main menu bar.
+ *
+ * $LicenseInfo:firstyear=2002&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 "llviewermenufile.h"
+
+// project includes
+#include "llagent.h"
+#include "llagentbenefits.h"
+#include "llagentcamera.h"
+#include "llfilepicker.h"
+#include "llfloaterreg.h"
+#include "llbuycurrencyhtml.h"
+#include "llfloatermap.h"
+#include "llfloatermodelpreview.h"
+#include "llmaterialeditor.h"
+#include "llfloaterperms.h"
+#include "llfloatersnapshot.h"
+#include "llfloatersimplesnapshot.h"
+#include "llimage.h"
+#include "llimagebmp.h"
+#include "llimagepng.h"
+#include "llimagej2c.h"
+#include "llimagejpeg.h"
+#include "llimagetga.h"
+#include "llinventorymodel.h" // gInventory
+#include "llpluginclassmedia.h"
+#include "llresourcedata.h"
+#include "llstatusbar.h"
+#include "lltinygltfhelper.h"
+#include "lltoast.h"
+#include "llviewercontrol.h" // gSavedSettings
+#include "llviewertexturelist.h"
+#include "lluictrlfactory.h"
+#include "llviewerinventory.h"
+#include "llviewermenu.h" // gMenuHolder
+#include "llviewerparcelmgr.h"
+#include "llviewerregion.h"
+#include "llviewerstats.h"
+#include "llviewerwindow.h"
+#include "llappviewer.h"
+#include "lluploaddialog.h"
+#include "lltrans.h"
+#include "llfloaterbuycurrency.h"
+#include "llviewerassetupload.h"
+
+// linden libraries
+#include "llnotificationsutil.h"
+#include "llsdserialize.h"
+#include "llsdutil.h"
+#include "llstring.h"
+#include "lltransactiontypes.h"
+#include "lluuid.h"
+#include "llvorbisencode.h"
+#include "message.h"
+
+// system libraries
+#include <boost/tokenizer.hpp>
+
+class LLFileEnableUpload : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ return true;
+ }
+};
+
+class LLFileEnableUploadModel : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ LLFloaterModelPreview* fmp = (LLFloaterModelPreview*) LLFloaterReg::findInstance("upload_model");
+ if (fmp && fmp->isModelLoading())
+ {
+ return false;
+ }
+
+ return true;
+ }
+};
+
+class LLFileEnableUploadMaterial : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ if (gAgent.getRegionCapability("UpdateMaterialAgentInventory").empty())
+ {
+ return false;
+ }
+
+ return true;
+ }
+};
+
+class LLMeshEnabled : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ return gSavedSettings.getBOOL("MeshEnabled");
+ }
+};
+
+class LLMeshUploadVisible : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ return gMeshRepo.meshUploadEnabled();
+ }
+};
+
+LLMutex* LLFilePickerThread::sMutex = NULL;
+std::queue<LLFilePickerThread*> LLFilePickerThread::sDeadQ;
+
+void LLFilePickerThread::getFile()
+{
+#if LL_WINDOWS
+ // Todo: get rid of LLFilePickerThread and make this modeless
+ start();
+#elif LL_DARWIN
+ runModeless();
+#else
+ run();
+#endif
+}
+
+//virtual
+void LLFilePickerThread::run()
+{
+#if LL_WINDOWS
+ bool blocking = false;
+#else
+ bool blocking = true; // modal
+#endif
+
+ LLFilePicker picker;
+
+ if (mIsSaveDialog)
+ {
+ if (picker.getSaveFile(mSaveFilter, mProposedName, blocking))
+ {
+ mResponses.push_back(picker.getFirstFile());
+ }
+ }
+ else
+ {
+ bool result = mIsGetMultiple ? picker.getMultipleOpenFiles(mLoadFilter, blocking) : picker.getOpenFile(mLoadFilter, blocking);
+ if (result)
+ {
+ std::string filename = picker.getFirstFile(); // consider copying mFiles directly
+ do
+ {
+ mResponses.push_back(filename);
+ filename = picker.getNextFile();
+ }
+ while (mIsGetMultiple && !filename.empty());
+ }
+ }
+
+ {
+ LLMutexLock lock(sMutex);
+ sDeadQ.push(this);
+ }
+}
+
+void LLFilePickerThread::runModeless()
+{
+ bool result = false;
+ LLFilePicker picker;
+
+ if (mIsSaveDialog)
+ {
+ result = picker.getSaveFileModeless(mSaveFilter,
+ mProposedName,
+ modelessStringCallback,
+ this);
+ }
+ else if (mIsGetMultiple)
+ {
+ result = picker.getMultipleOpenFilesModeless(mLoadFilter, modelessVectorCallback, this);
+ }
+ else
+ {
+ result = picker.getOpenFileModeless(mLoadFilter, modelessVectorCallback, this);
+ }
+
+ if (!result)
+ {
+ LLMutexLock lock(sMutex);
+ sDeadQ.push(this);
+ }
+}
+
+void LLFilePickerThread::modelessStringCallback(bool success,
+ std::string &response,
+ void *user_data)
+{
+ LLFilePickerThread *picker = (LLFilePickerThread*)user_data;
+ if (success)
+ {
+ picker->mResponses.push_back(response);
+ }
+
+ {
+ LLMutexLock lock(sMutex);
+ sDeadQ.push(picker);
+ }
+}
+
+void LLFilePickerThread::modelessVectorCallback(bool success,
+ std::vector<std::string> &responses,
+ void *user_data)
+{
+ LLFilePickerThread *picker = (LLFilePickerThread*)user_data;
+ if (success)
+ {
+ if (picker->mIsGetMultiple)
+ {
+ picker->mResponses = responses;
+ }
+ else
+ {
+ std::vector<std::string>::iterator iter = responses.begin();
+ while (iter != responses.end())
+ {
+ if (!iter->empty())
+ {
+ picker->mResponses.push_back(*iter);
+ break;
+ }
+ iter++;
+ }
+ }
+ }
+
+ {
+ LLMutexLock lock(sMutex);
+ sDeadQ.push(picker);
+ }
+}
+
+//static
+void LLFilePickerThread::initClass()
+{
+ sMutex = new LLMutex();
+}
+
+//static
+void LLFilePickerThread::cleanupClass()
+{
+ clearDead();
+
+ delete sMutex;
+ sMutex = NULL;
+}
+
+//static
+void LLFilePickerThread::clearDead()
+{
+ if (!sDeadQ.empty())
+ {
+ LLMutexLock lock(sMutex);
+ while (!sDeadQ.empty())
+ {
+ LLFilePickerThread* thread = sDeadQ.front();
+ thread->notify(thread->mResponses);
+ delete thread;
+ sDeadQ.pop();
+ }
+ }
+}
+
+LLFilePickerReplyThread::LLFilePickerReplyThread(const file_picked_signal_t::slot_type& cb, LLFilePicker::ELoadFilter filter, bool get_multiple, const file_picked_signal_t::slot_type& failure_cb)
+ : LLFilePickerThread(filter, get_multiple),
+ mLoadFilter(filter),
+ mSaveFilter(LLFilePicker::FFSAVE_ALL),
+ mFilePickedSignal(NULL),
+ mFailureSignal(NULL)
+{
+ mFilePickedSignal = new file_picked_signal_t();
+ mFilePickedSignal->connect(cb);
+
+ mFailureSignal = new file_picked_signal_t();
+ mFailureSignal->connect(failure_cb);
+}
+
+LLFilePickerReplyThread::LLFilePickerReplyThread(const file_picked_signal_t::slot_type& cb, LLFilePicker::ESaveFilter filter, const std::string &proposed_name, const file_picked_signal_t::slot_type& failure_cb)
+ : LLFilePickerThread(filter, proposed_name),
+ mLoadFilter(LLFilePicker::FFLOAD_ALL),
+ mSaveFilter(filter),
+ mFilePickedSignal(NULL),
+ mFailureSignal(NULL)
+{
+ mFilePickedSignal = new file_picked_signal_t();
+ mFilePickedSignal->connect(cb);
+
+ mFailureSignal = new file_picked_signal_t();
+ mFailureSignal->connect(failure_cb);
+}
+
+LLFilePickerReplyThread::~LLFilePickerReplyThread()
+{
+ delete mFilePickedSignal;
+ delete mFailureSignal;
+}
+
+void LLFilePickerReplyThread::startPicker(const file_picked_signal_t::slot_type & cb, LLFilePicker::ELoadFilter filter, bool get_multiple, const file_picked_signal_t::slot_type & failure_cb)
+{
+ (new LLFilePickerReplyThread(cb, filter, get_multiple, failure_cb))->getFile();
+}
+
+void LLFilePickerReplyThread::startPicker(const file_picked_signal_t::slot_type & cb, LLFilePicker::ESaveFilter filter, const std::string & proposed_name, const file_picked_signal_t::slot_type & failure_cb)
+{
+ (new LLFilePickerReplyThread(cb, filter, proposed_name, failure_cb))->getFile();
+}
+
+void LLFilePickerReplyThread::notify(const std::vector<std::string>& filenames)
+{
+ if (filenames.empty())
+ {
+ if (mFailureSignal)
+ {
+ (*mFailureSignal)(filenames, mLoadFilter, mSaveFilter);
+ }
+ }
+ else
+ {
+ if (mFilePickedSignal)
+ {
+ (*mFilePickedSignal)(filenames, mLoadFilter, mSaveFilter);
+ }
+ }
+}
+
+
+LLMediaFilePicker::LLMediaFilePicker(LLPluginClassMedia* plugin, LLFilePicker::ELoadFilter filter, bool get_multiple)
+ : LLFilePickerThread(filter, get_multiple),
+ mPlugin(plugin->getSharedPtr())
+{
+}
+
+LLMediaFilePicker::LLMediaFilePicker(LLPluginClassMedia* plugin, LLFilePicker::ESaveFilter filter, const std::string &proposed_name)
+ : LLFilePickerThread(filter, proposed_name),
+ mPlugin(plugin->getSharedPtr())
+{
+}
+
+void LLMediaFilePicker::notify(const std::vector<std::string>& filenames)
+{
+ mPlugin->sendPickFileResponse(mResponses);
+ mPlugin = NULL;
+}
+
+//============================================================================
+
+#if LL_WINDOWS
+static std::string SOUND_EXTENSIONS = "wav";
+static std::string IMAGE_EXTENSIONS = "tga bmp jpg jpeg png";
+static std::string ANIM_EXTENSIONS = "bvh anim";
+static std::string XML_EXTENSIONS = "xml";
+static std::string SLOBJECT_EXTENSIONS = "slobject";
+#endif
+static std::string ALL_FILE_EXTENSIONS = "*.*";
+static std::string MODEL_EXTENSIONS = "dae";
+static std::string MATERIAL_EXTENSIONS = "gltf glb";
+
+std::string build_extensions_string(LLFilePicker::ELoadFilter filter)
+{
+ switch(filter)
+ {
+#if LL_WINDOWS
+ case LLFilePicker::FFLOAD_IMAGE:
+ return IMAGE_EXTENSIONS;
+ case LLFilePicker::FFLOAD_WAV:
+ return SOUND_EXTENSIONS;
+ case LLFilePicker::FFLOAD_ANIM:
+ return ANIM_EXTENSIONS;
+ case LLFilePicker::FFLOAD_SLOBJECT:
+ return SLOBJECT_EXTENSIONS;
+ case LLFilePicker::FFLOAD_MODEL:
+ return MODEL_EXTENSIONS;
+ case LLFilePicker::FFLOAD_MATERIAL:
+ return MATERIAL_EXTENSIONS;
+ case LLFilePicker::FFLOAD_XML:
+ return XML_EXTENSIONS;
+ case LLFilePicker::FFLOAD_ALL:
+ case LLFilePicker::FFLOAD_EXE:
+ return ALL_FILE_EXTENSIONS;
+#endif
+ default:
+ return ALL_FILE_EXTENSIONS;
+ }
+}
+
+
+const bool check_file_extension(const std::string& filename, LLFilePicker::ELoadFilter type)
+{
+ std::string ext = gDirUtilp->getExtension(filename);
+
+ //strincmp doesn't like NULL pointers
+ if (ext.empty())
+ {
+ std::string short_name = gDirUtilp->getBaseFileName(filename);
+
+ // No extension
+ LLSD args;
+ args["FILE"] = short_name;
+ LLNotificationsUtil::add("NoFileExtension", args);
+ return false;
+ }
+ else
+ {
+ //so there is an extension
+ //loop over the valid extensions and compare to see
+ //if the extension is valid
+
+ //now grab the set of valid file extensions
+ std::string valid_extensions = build_extensions_string(type);
+
+ bool ext_valid = false;
+
+ typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
+ boost::char_separator<char> sep(" ");
+ tokenizer tokens(valid_extensions, sep);
+ tokenizer::iterator token_iter;
+
+ //now loop over all valid file extensions
+ //and compare them to the extension of the file
+ //to be uploaded
+ for (token_iter = tokens.begin();
+ token_iter != tokens.end() && !ext_valid;
+ ++token_iter)
+ {
+ const std::string& cur_token = *token_iter;
+
+ if (cur_token == ext || cur_token == "*.*")
+ {
+ //valid extension
+ //or the acceptable extension is any
+ ext_valid = true;
+ }
+ }//end for (loop over all tokens)
+
+ if (!ext_valid)
+ {
+ //should only get here if the extension exists
+ //but is invalid
+ LLSD args;
+ args["EXTENSION"] = ext;
+ args["VALIDS"] = valid_extensions;
+ LLNotificationsUtil::add("InvalidFileExtension", args);
+ return false;
+ }
+ }//end else (non-null extension)
+ return true;
+}
+
+const void upload_single_file(const std::vector<std::string>& filenames, LLFilePicker::ELoadFilter type)
+{
+ std::string filename = filenames[0];
+ if (!check_file_extension(filename, type)) return;
+
+ if (!filename.empty())
+ {
+ if (type == LLFilePicker::FFLOAD_WAV)
+ {
+ // pre-qualify wavs to make sure the format is acceptable
+ std::string error_msg;
+ if (check_for_invalid_wav_formats(filename, error_msg))
+ {
+ LL_INFOS() << error_msg << ": " << filename << LL_ENDL;
+ LLSD args;
+ args["FILE"] = filename;
+ LLNotificationsUtil::add(error_msg, args);
+ return;
+ }
+ else
+ {
+ LLFloaterReg::showInstance("upload_sound", LLSD(filename));
+ }
+ }
+ if (type == LLFilePicker::FFLOAD_IMAGE)
+ {
+ LLFloaterReg::showInstance("upload_image", LLSD(filename));
+ }
+ if (type == LLFilePicker::FFLOAD_ANIM)
+ {
+ std::string filename_lc(filename);
+ LLStringUtil::toLower(filename_lc);
+ if (filename_lc.rfind(".anim") != std::string::npos)
+ {
+ LLFloaterReg::showInstance("upload_anim_anim", LLSD(filename));
+ }
+ else
+ {
+ LLFloaterReg::showInstance("upload_anim_bvh", LLSD(filename));
+ }
+ }
+ }
+ return;
+}
+
+void do_bulk_upload(std::vector<std::string> filenames, const LLSD& notification, const LLSD& response)
+{
+ S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
+ if (option != 0)
+ {
+ // Cancel upload
+ return;
+ }
+
+ for (std::vector<std::string>::const_iterator in_iter = filenames.begin(); in_iter != filenames.end(); ++in_iter)
+ {
+ std::string filename = (*in_iter);
+
+ std::string name = gDirUtilp->getBaseFileName(filename, true);
+ std::string asset_name = name;
+ LLStringUtil::replaceNonstandardASCII(asset_name, '?');
+ LLStringUtil::replaceChar(asset_name, '|', '?');
+ LLStringUtil::stripNonprintable(asset_name);
+ LLStringUtil::trim(asset_name);
+
+ std::string ext = gDirUtilp->getExtension(filename);
+ LLAssetType::EType asset_type;
+ U32 codec;
+ S32 expected_upload_cost;
+ if (LLResourceUploadInfo::findAssetTypeAndCodecOfExtension(ext, asset_type, codec) &&
+ LLAgentBenefitsMgr::current().findUploadCost(asset_type, expected_upload_cost))
+ {
+ LLResourceUploadInfo::ptr_t uploadInfo(new LLNewFileResourceUploadInfo(
+ filename,
+ asset_name,
+ asset_name, 0,
+ LLFolderType::FT_NONE, LLInventoryType::IT_NONE,
+ LLFloaterPerms::getNextOwnerPerms("Uploads"),
+ LLFloaterPerms::getGroupPerms("Uploads"),
+ LLFloaterPerms::getEveryonePerms("Uploads"),
+ expected_upload_cost));
+
+ upload_new_resource(uploadInfo);
+ }
+
+ // gltf does not use normal upload procedure
+ if (ext == "gltf" || ext == "glb")
+ {
+ tinygltf::Model model;
+ if (LLTinyGLTFHelper::loadModel(filename, model))
+ {
+ S32 materials_in_file = model.materials.size();
+
+ for (S32 i = 0; i < materials_in_file; i++)
+ {
+ // Todo:
+ // 1. Decouple bulk upload from material editor
+ // 2. Take into account possiblity of identical textures
+ LLMaterialEditor::uploadMaterialFromModel(filename, model, i);
+ }
+ }
+ }
+ }
+}
+
+bool get_bulk_upload_expected_cost(const std::vector<std::string>& filenames, S32& total_cost, S32& file_count, S32& bvh_count)
+{
+ total_cost = 0;
+ file_count = 0;
+ bvh_count = 0;
+ for (std::vector<std::string>::const_iterator in_iter = filenames.begin(); in_iter != filenames.end(); ++in_iter)
+ {
+ std::string filename = (*in_iter);
+ std::string ext = gDirUtilp->getExtension(filename);
+
+ if (ext == "bvh")
+ {
+ bvh_count++;
+ }
+
+ LLAssetType::EType asset_type;
+ U32 codec;
+ S32 cost;
+
+ if (LLResourceUploadInfo::findAssetTypeAndCodecOfExtension(ext, asset_type, codec) &&
+ LLAgentBenefitsMgr::current().findUploadCost(asset_type, cost))
+ {
+ total_cost += cost;
+ file_count++;
+ }
+
+ if (ext == "gltf" || ext == "glb")
+ {
+ S32 texture_upload_cost = LLAgentBenefitsMgr::current().getTextureUploadCost();
+
+ tinygltf::Model model;
+
+ if (LLTinyGLTFHelper::loadModel(filename, model))
+ {
+ S32 materials_in_file = model.materials.size();
+
+ for (S32 i = 0; i < materials_in_file; i++)
+ {
+ LLPointer<LLFetchedGLTFMaterial> material = new LLFetchedGLTFMaterial();
+ std::string material_name;
+ bool decode_successful = LLTinyGLTFHelper::getMaterialFromModel(filename, model, i, material.get(), material_name);
+
+ if (decode_successful)
+ {
+ // Todo: make it account for possibility of same texture in different
+ // materials and even in scope of same material
+ S32 texture_count = 0;
+ if (material->mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_BASE_COLOR].notNull())
+ {
+ texture_count++;
+ }
+ if (material->mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_METALLIC_ROUGHNESS].notNull())
+ {
+ texture_count++;
+ }
+ if (material->mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_NORMAL].notNull())
+ {
+ texture_count++;
+ }
+ if (material->mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_EMISSIVE].notNull())
+ {
+ texture_count++;
+ }
+ total_cost += texture_count * texture_upload_cost;
+ file_count++;
+ }
+ }
+ }
+ }
+ }
+
+ return file_count > 0;
+}
+
+const void upload_bulk(const std::vector<std::string>& filenames, LLFilePicker::ELoadFilter type)
+{
+ // TODO:
+ // Check user balance for entire cost
+ // Charge user entire cost
+ // Loop, uploading
+ // If an upload fails, refund the user for that one
+ //
+ // Also fix single upload to charge first, then refund
+
+ // FIXME PREMIUM what about known types that can't be bulk uploaded
+ // (bvh)? These will fail in the item by item upload but won't be
+ // mentioned in the notification.
+ std::vector<std::string> filtered_filenames;
+ for (std::vector<std::string>::const_iterator in_iter = filenames.begin(); in_iter != filenames.end(); ++in_iter)
+ {
+ const std::string& filename = *in_iter;
+ if (check_file_extension(filename, type))
+ {
+ filtered_filenames.push_back(filename);
+ }
+ }
+
+ S32 expected_upload_cost;
+ S32 expected_upload_count;
+ S32 bvh_count;
+ if (get_bulk_upload_expected_cost(filtered_filenames, expected_upload_cost, expected_upload_count, bvh_count))
+ {
+ LLSD args;
+ args["COST"] = expected_upload_cost;
+ args["COUNT"] = expected_upload_count;
+ LLNotificationsUtil::add("BulkUploadCostConfirmation", args, LLSD(), boost::bind(do_bulk_upload, filtered_filenames, _1, _2));
+
+ if (filtered_filenames.size() > expected_upload_count)
+ {
+ if (bvh_count == filtered_filenames.size() - expected_upload_count)
+ {
+ LLNotificationsUtil::add("DoNotSupportBulkAnimationUpload");
+ }
+ else
+ {
+ LLNotificationsUtil::add("BulkUploadIncompatibleFiles");
+ }
+ }
+ }
+ else if (bvh_count == filtered_filenames.size())
+ {
+ LLNotificationsUtil::add("DoNotSupportBulkAnimationUpload");
+ }
+ else
+ {
+ LLNotificationsUtil::add("BulkUploadNoCompatibleFiles");
+ }
+
+}
+
+class LLFileUploadImage : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ if (gAgentCamera.cameraMouselook())
+ {
+ gAgentCamera.changeCameraToDefault();
+ }
+ LLFilePickerReplyThread::startPicker(boost::bind(&upload_single_file, _1, _2), LLFilePicker::FFLOAD_IMAGE, false);
+ return true;
+ }
+};
+
+class LLFileUploadModel : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ LLFloaterModelPreview::showModelPreview();
+ return true;
+ }
+};
+
+class LLFileUploadMaterial : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ LLMaterialEditor::importMaterial();
+ return true;
+ }
+};
+
+class LLFileUploadSound : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ if (gAgentCamera.cameraMouselook())
+ {
+ gAgentCamera.changeCameraToDefault();
+ }
+ LLFilePickerReplyThread::startPicker(boost::bind(&upload_single_file, _1, _2), LLFilePicker::FFLOAD_WAV, false);
+ return true;
+ }
+};
+
+class LLFileUploadAnim : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ if (gAgentCamera.cameraMouselook())
+ {
+ gAgentCamera.changeCameraToDefault();
+ }
+ LLFilePickerReplyThread::startPicker(boost::bind(&upload_single_file, _1, _2), LLFilePicker::FFLOAD_ANIM, false);
+ return true;
+ }
+};
+
+class LLFileUploadBulk : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ if (gAgentCamera.cameraMouselook())
+ {
+ gAgentCamera.changeCameraToDefault();
+ }
+ LLFilePickerReplyThread::startPicker(boost::bind(&upload_bulk, _1, _2), LLFilePicker::FFLOAD_ALL, true);
+ return true;
+ }
+};
+
+void upload_error(const std::string& error_message, const std::string& label, const std::string& filename, const LLSD& args)
+{
+ LL_WARNS() << error_message << LL_ENDL;
+ LLNotificationsUtil::add(label, args);
+ if(LLFile::remove(filename) == -1)
+ {
+ LL_DEBUGS() << "unable to remove temp file" << LL_ENDL;
+ }
+ LLFilePicker::instance().reset();
+}
+
+class LLFileEnableCloseWindow : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ bool frontmost_fl_exists = (NULL != gFloaterView->getFrontmostClosableFloater());
+ bool frontmost_snapshot_fl_exists = (NULL != gSnapshotFloaterView->getFrontmostClosableFloater());
+
+ return !LLNotificationsUI::LLToast::isAlertToastShown() && (frontmost_fl_exists || frontmost_snapshot_fl_exists);
+ }
+};
+
+class LLFileCloseWindow : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ bool frontmost_fl_exists = (NULL != gFloaterView->getFrontmostClosableFloater());
+ LLFloater* snapshot_floater = gSnapshotFloaterView->getFrontmostClosableFloater();
+
+ if(snapshot_floater && (!frontmost_fl_exists || snapshot_floater->hasFocus()))
+ {
+ snapshot_floater->closeFloater();
+ if (gFocusMgr.getKeyboardFocus() == NULL)
+ {
+ gFloaterView->focusFrontFloater();
+ }
+ }
+ else
+ {
+ LLFloater::closeFrontmostFloater();
+ }
+ if (gMenuHolder) gMenuHolder->hideMenus();
+ return true;
+ }
+};
+
+class LLFileEnableCloseAllWindows : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ LLFloaterSnapshot* floater_snapshot = LLFloaterSnapshot::findInstance();
+ bool is_floaters_snapshot_opened = (floater_snapshot && floater_snapshot->isInVisibleChain());
+ bool open_children = gFloaterView->allChildrenClosed() && !is_floaters_snapshot_opened;
+ return !open_children && !LLNotificationsUI::LLToast::isAlertToastShown();
+ }
+};
+
+class LLFileCloseAllWindows : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ bool app_quitting = false;
+ gFloaterView->closeAllChildren(app_quitting);
+ LLFloaterSnapshot* floater_snapshot = LLFloaterSnapshot::findInstance();
+ if (floater_snapshot)
+ floater_snapshot->closeFloater(app_quitting);
+ if (gMenuHolder) gMenuHolder->hideMenus();
+ return true;
+ }
+};
+
+class LLFileTakeSnapshotToDisk : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ LLPointer<LLImageRaw> raw = new LLImageRaw;
+
+ S32 width = gViewerWindow->getWindowWidthRaw();
+ S32 height = gViewerWindow->getWindowHeightRaw();
+
+ bool render_ui = gSavedSettings.getBOOL("RenderUIInSnapshot");
+ bool render_hud = gSavedSettings.getBOOL("RenderHUDInSnapshot");
+ bool render_no_post = gSavedSettings.getBOOL("RenderSnapshotNoPost");
+
+ bool high_res = gSavedSettings.getBOOL("HighResSnapshot");
+ if (high_res)
+ {
+ width *= 2;
+ height *= 2;
+ // not compatible with UI/HUD
+ render_ui = false;
+ render_hud = false;
+ }
+
+ if (gViewerWindow->rawSnapshot(raw,
+ width,
+ height,
+ true,
+ false,
+ render_ui,
+ render_hud,
+ false,
+ render_no_post,
+ LLSnapshotModel::SNAPSHOT_TYPE_COLOR,
+ high_res ? S32_MAX : MAX_SNAPSHOT_IMAGE_SIZE)) //per side
+ {
+ LLPointer<LLImageFormatted> formatted;
+ LLSnapshotModel::ESnapshotFormat fmt = (LLSnapshotModel::ESnapshotFormat) gSavedSettings.getS32("SnapshotFormat");
+ switch (fmt)
+ {
+ case LLSnapshotModel::SNAPSHOT_FORMAT_JPEG:
+ formatted = new LLImageJPEG(gSavedSettings.getS32("SnapshotQuality"));
+ break;
+ default:
+ LL_WARNS() << "Unknown local snapshot format: " << fmt << LL_ENDL;
+ case LLSnapshotModel::SNAPSHOT_FORMAT_PNG:
+ formatted = new LLImagePNG;
+ break;
+ case LLSnapshotModel::SNAPSHOT_FORMAT_BMP:
+ formatted = new LLImageBMP;
+ break;
+ }
+ formatted->enableOverSize() ;
+ formatted->encode(raw, 0);
+ formatted->disableOverSize() ;
+ LLSnapshotLivePreview::saveLocal(formatted);
+ }
+ return true;
+ }
+};
+
+class LLFileQuit : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ LLAppViewer::instance()->userQuit();
+ return true;
+ }
+};
+
+
+void handle_compress_image(void*)
+{
+ LLFilePicker& picker = LLFilePicker::instance();
+ if (picker.getMultipleOpenFiles(LLFilePicker::FFLOAD_IMAGE))
+ {
+ std::string infile = picker.getFirstFile();
+ while (!infile.empty())
+ {
+ std::string outfile = infile + ".j2c";
+
+ LL_INFOS() << "Input: " << infile << LL_ENDL;
+ LL_INFOS() << "Output: " << outfile << LL_ENDL;
+
+ bool success;
+
+ success = LLViewerTextureList::createUploadFile(infile, outfile, IMG_CODEC_TGA);
+
+ if (success)
+ {
+ LL_INFOS() << "Compression complete" << LL_ENDL;
+ }
+ else
+ {
+ LL_INFOS() << "Compression failed: " << LLImage::getLastThreadError() << LL_ENDL;
+ }
+
+ infile = picker.getNextFile();
+ }
+ }
+}
+
+// No convinient check in LLFile, and correct way would be something
+// like GetFileSizeEx, which is too OS specific for current purpose
+// so doing dirty, but OS independent fopen and fseek
+size_t get_file_size(std::string &filename)
+{
+ LLFILE* file = LLFile::fopen(filename, "rb"); /*Flawfinder: ignore*/
+ if (!file)
+ {
+ LL_WARNS() << "Error opening " << filename << LL_ENDL;
+ return 0;
+ }
+
+ // read in the whole file
+ fseek(file, 0L, SEEK_END);
+ size_t file_length = (size_t)ftell(file);
+ fclose(file);
+ return file_length;
+}
+
+void handle_compress_file_test(void*)
+{
+ LLFilePicker& picker = LLFilePicker::instance();
+ if (picker.getOpenFile())
+ {
+ std::string infile = picker.getFirstFile();
+ if (!infile.empty())
+ {
+ std::string packfile = infile + ".pack_test";
+ std::string unpackfile = infile + ".unpack_test";
+
+ S64Bytes initial_size = S64Bytes(get_file_size(infile));
+
+ bool success;
+
+ F64 total_seconds = LLTimer::getTotalSeconds();
+ success = gzip_file(infile, packfile);
+ F64 result_pack_seconds = LLTimer::getTotalSeconds() - total_seconds;
+
+ if (success)
+ {
+ S64Bytes packed_size = S64Bytes(get_file_size(packfile));
+
+ LL_INFOS() << "Packing complete, time: " << result_pack_seconds << " size: " << packed_size << LL_ENDL;
+ total_seconds = LLTimer::getTotalSeconds();
+ success = gunzip_file(packfile, unpackfile);
+ F64 result_unpack_seconds = LLTimer::getTotalSeconds() - total_seconds;
+
+ if (success)
+ {
+ S64Bytes unpacked_size = S64Bytes(get_file_size(unpackfile));
+
+ LL_INFOS() << "Unpacking complete, time: " << result_unpack_seconds << " size: " << unpacked_size << LL_ENDL;
+
+ LLSD args;
+ args["FILE"] = infile;
+ args["PACK_TIME"] = result_pack_seconds;
+ args["UNPACK_TIME"] = result_unpack_seconds;
+ args["SIZE"] = LLSD::Integer(initial_size.valueInUnits<LLUnits::Kilobytes>());
+ args["PSIZE"] = LLSD::Integer(packed_size.valueInUnits<LLUnits::Kilobytes>());
+ args["USIZE"] = LLSD::Integer(unpacked_size.valueInUnits<LLUnits::Kilobytes>());
+ LLNotificationsUtil::add("CompressionTestResults", args);
+
+ LLFile::remove(packfile);
+ LLFile::remove(unpackfile);
+ }
+ else
+ {
+ LL_INFOS() << "Failed to uncompress file: " << packfile << LL_ENDL;
+ LLFile::remove(packfile);
+ }
+
+ }
+ else
+ {
+ LL_INFOS() << "Failed to compres file: " << infile << LL_ENDL;
+ }
+ }
+ else
+ {
+ LL_INFOS() << "Failed to open file" << LL_ENDL;
+ }
+ }
+ else
+ {
+ LL_INFOS() << "Failed to open file" << LL_ENDL;
+ }
+}
+
+
+LLUUID upload_new_resource(
+ const std::string& src_filename,
+ std::string name,
+ std::string desc,
+ S32 compression_info,
+ LLFolderType::EType destination_folder_type,
+ LLInventoryType::EType inv_type,
+ U32 next_owner_perms,
+ U32 group_perms,
+ U32 everyone_perms,
+ const std::string& display_name,
+ LLAssetStorage::LLStoreAssetCallback callback,
+ S32 expected_upload_cost,
+ void *userdata,
+ bool show_inventory)
+{
+
+ LLResourceUploadInfo::ptr_t uploadInfo(std::make_shared<LLNewFileResourceUploadInfo>(
+ src_filename,
+ name, desc, compression_info,
+ destination_folder_type, inv_type,
+ next_owner_perms, group_perms, everyone_perms,
+ expected_upload_cost, show_inventory));
+ upload_new_resource(uploadInfo, callback, userdata);
+
+ return LLUUID::null;
+}
+
+void upload_done_callback(
+ const LLUUID& uuid,
+ void* user_data,
+ S32 result,
+ LLExtStat ext_status) // StoreAssetData callback (fixed)
+{
+ LLResourceData* data = (LLResourceData*)user_data;
+ S32 expected_upload_cost = data ? data->mExpectedUploadCost : 0;
+ //LLAssetType::EType pref_loc = data->mPreferredLocation;
+ bool is_balance_sufficient = true;
+
+ if(data)
+ {
+ if (result >= 0)
+ {
+ LLFolderType::EType dest_loc = (data->mPreferredLocation == LLFolderType::FT_NONE) ? LLFolderType::assetTypeToFolderType(data->mAssetInfo.mType) : data->mPreferredLocation;
+
+ if (LLAssetType::AT_SOUND == data->mAssetInfo.mType ||
+ LLAssetType::AT_TEXTURE == data->mAssetInfo.mType ||
+ LLAssetType::AT_ANIMATION == data->mAssetInfo.mType)
+ {
+ // Charge the user for the upload.
+ LLViewerRegion* region = gAgent.getRegion();
+
+ if(!(can_afford_transaction(expected_upload_cost)))
+ {
+ LLBuyCurrencyHTML::openCurrencyFloater( "", expected_upload_cost );
+ is_balance_sufficient = false;
+ }
+ else if(region)
+ {
+ // Charge user for upload
+ gStatusBar->debitBalance(expected_upload_cost);
+
+ LLMessageSystem* msg = gMessageSystem;
+ msg->newMessageFast(_PREHASH_MoneyTransferRequest);
+ msg->nextBlockFast(_PREHASH_AgentData);
+ msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
+ msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
+ msg->nextBlockFast(_PREHASH_MoneyData);
+ msg->addUUIDFast(_PREHASH_SourceID, gAgent.getID());
+ msg->addUUIDFast(_PREHASH_DestID, LLUUID::null);
+ msg->addU8("Flags", 0);
+ // we tell the sim how much we were expecting to pay so it
+ // can respond to any discrepancy
+ msg->addS32Fast(_PREHASH_Amount, expected_upload_cost);
+ msg->addU8Fast(_PREHASH_AggregatePermNextOwner, (U8)LLAggregatePermissions::AP_EMPTY);
+ msg->addU8Fast(_PREHASH_AggregatePermInventory, (U8)LLAggregatePermissions::AP_EMPTY);
+ msg->addS32Fast(_PREHASH_TransactionType, TRANS_UPLOAD_CHARGE);
+ msg->addStringFast(_PREHASH_Description, NULL);
+ msg->sendReliable(region->getHost());
+ }
+ }
+
+ if(is_balance_sufficient)
+ {
+ // Actually add the upload to inventory
+ LL_INFOS() << "Adding " << uuid << " to inventory." << LL_ENDL;
+ const LLUUID folder_id = gInventory.findCategoryUUIDForType(dest_loc);
+ if(folder_id.notNull())
+ {
+ U32 next_owner_perms = data->mNextOwnerPerm;
+ if(PERM_NONE == next_owner_perms)
+ {
+ next_owner_perms = PERM_MOVE | PERM_TRANSFER;
+ }
+ create_inventory_item(gAgent.getID(), gAgent.getSessionID(),
+ folder_id, data->mAssetInfo.mTransactionID, data->mAssetInfo.getName(),
+ data->mAssetInfo.getDescription(), data->mAssetInfo.mType,
+ data->mInventoryType, NO_INV_SUBTYPE, next_owner_perms,
+ LLPointer<LLInventoryCallback>(NULL));
+ }
+ else
+ {
+ LL_WARNS() << "Can't find a folder to put it in" << LL_ENDL;
+ }
+ }
+ }
+ else // if(result >= 0)
+ {
+ LLSD args;
+ args["FILE"] = LLInventoryType::lookupHumanReadable(data->mInventoryType);
+ args["REASON"] = std::string(LLAssetStorage::getErrorString(result));
+ LLNotificationsUtil::add("CannotUploadReason", args);
+ }
+
+ delete data;
+ data = NULL;
+ }
+
+ LLUploadDialog::modalUploadFinished();
+
+ // *NOTE: This is a pretty big hack. What this does is check the
+ // file picker if there are any more pending uploads. If so,
+ // upload that file.
+ const std::string& next_file = LLFilePicker::instance().getNextFile();
+ if(is_balance_sufficient && !next_file.empty())
+ {
+ std::string asset_name = gDirUtilp->getBaseFileName(next_file, true);
+ LLStringUtil::replaceNonstandardASCII( asset_name, '?' );
+ LLStringUtil::replaceChar(asset_name, '|', '?');
+ LLStringUtil::stripNonprintable(asset_name);
+ LLStringUtil::trim(asset_name);
+
+ std::string display_name = LLStringUtil::null;
+ LLAssetStorage::LLStoreAssetCallback callback;
+ void *userdata = NULL;
+ upload_new_resource(
+ next_file,
+ asset_name,
+ asset_name, // file
+ 0,
+ LLFolderType::FT_NONE,
+ LLInventoryType::IT_NONE,
+ LLFloaterPerms::getNextOwnerPerms("Uploads"),
+ LLFloaterPerms::getGroupPerms("Uploads"),
+ LLFloaterPerms::getEveryonePerms("Uploads"),
+ display_name,
+ callback,
+ expected_upload_cost, // assuming next in a group of uploads is of roughly the same type, i.e. same upload cost
+ userdata);
+ }
+}
+
+void upload_new_resource(
+ LLResourceUploadInfo::ptr_t &uploadInfo,
+ LLAssetStorage::LLStoreAssetCallback callback,
+ void *userdata)
+{
+ if(gDisconnected)
+ {
+ return ;
+ }
+
+// uploadInfo->setAssetType(assetType);
+// uploadInfo->setTransactionId(tid);
+
+
+ std::string url = gAgent.getRegionCapability("NewFileAgentInventory");
+
+ if ( !url.empty() )
+ {
+ LLViewerAssetUpload::EnqueueInventoryUpload(url, uploadInfo);
+ }
+ else
+ {
+ uploadInfo->prepareUpload();
+ uploadInfo->logPreparedUpload();
+
+ LL_INFOS() << "NewAgentInventory capability not found, new agent inventory via asset system." << LL_ENDL;
+ // check for adequate funds
+ // TODO: do this check on the sim
+ if (LLAssetType::AT_SOUND == uploadInfo->getAssetType() ||
+ LLAssetType::AT_TEXTURE == uploadInfo->getAssetType() ||
+ LLAssetType::AT_ANIMATION == uploadInfo->getAssetType())
+ {
+ S32 balance = gStatusBar->getBalance();
+ if (balance < uploadInfo->getExpectedUploadCost())
+ {
+ // insufficient funds, bail on this upload
+ LLBuyCurrencyHTML::openCurrencyFloater("", uploadInfo->getExpectedUploadCost());
+ return;
+ }
+ }
+
+ LLResourceData* data = new LLResourceData;
+ data->mAssetInfo.mTransactionID = uploadInfo->getTransactionId();
+ data->mAssetInfo.mUuid = uploadInfo->getAssetId();
+ data->mAssetInfo.mType = uploadInfo->getAssetType();
+ data->mAssetInfo.mCreatorID = gAgentID;
+ data->mInventoryType = uploadInfo->getInventoryType();
+ data->mNextOwnerPerm = uploadInfo->getNextOwnerPerms();
+ data->mExpectedUploadCost = uploadInfo->getExpectedUploadCost();
+ data->mUserData = userdata;
+ data->mAssetInfo.setName(uploadInfo->getName());
+ data->mAssetInfo.setDescription(uploadInfo->getDescription());
+ data->mPreferredLocation = uploadInfo->getDestinationFolderType();
+
+ LLAssetStorage::LLStoreAssetCallback asset_callback = &upload_done_callback;
+ if (callback)
+ {
+ asset_callback = callback;
+ }
+ gAssetStorage->storeAssetData(
+ data->mAssetInfo.mTransactionID,
+ data->mAssetInfo.mType,
+ asset_callback,
+ (void*)data,
+ false);
+ }
+}
+
+
+void init_menu_file()
+{
+ view_listener_t::addCommit(new LLFileUploadImage(), "File.UploadImage");
+ view_listener_t::addCommit(new LLFileUploadSound(), "File.UploadSound");
+ view_listener_t::addCommit(new LLFileUploadAnim(), "File.UploadAnim");
+ view_listener_t::addCommit(new LLFileUploadModel(), "File.UploadModel");
+ view_listener_t::addCommit(new LLFileUploadMaterial(), "File.UploadMaterial");
+ view_listener_t::addCommit(new LLFileUploadBulk(), "File.UploadBulk");
+ view_listener_t::addCommit(new LLFileCloseWindow(), "File.CloseWindow");
+ view_listener_t::addCommit(new LLFileCloseAllWindows(), "File.CloseAllWindows");
+ view_listener_t::addEnable(new LLFileEnableCloseWindow(), "File.EnableCloseWindow");
+ view_listener_t::addEnable(new LLFileEnableCloseAllWindows(), "File.EnableCloseAllWindows");
+ view_listener_t::addCommit(new LLFileTakeSnapshotToDisk(), "File.TakeSnapshotToDisk");
+ view_listener_t::addCommit(new LLFileQuit(), "File.Quit");
+
+ view_listener_t::addEnable(new LLFileEnableUpload(), "File.EnableUpload");
+ view_listener_t::addEnable(new LLFileEnableUploadModel(), "File.EnableUploadModel");
+ view_listener_t::addEnable(new LLFileEnableUploadMaterial(), "File.EnableUploadMaterial");
+ view_listener_t::addMenu(new LLMeshEnabled(), "File.MeshEnabled");
+ view_listener_t::addMenu(new LLMeshUploadVisible(), "File.VisibleUploadModel");
+
+ // "File.SaveTexture" moved to llpanelmaininventory so that it can be properly handled.
+}