12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235 |
- /**
- * @file hbfileselector.cpp
- * @brief The HBFileSelector class definition
- *
- * $LicenseInfo:firstyear=2014&license=viewergpl$
- *
- * Copyright (c) 2014, Henri Beauchamp
- *
- * Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
- *
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at
- * http://secondlifegrid.net/programs/open_source/licensing/flossexception
- *
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
- *
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
- * $/LicenseInfo$
- */
- #include "linden_common.h"
- #include "hbfileselector.h"
- #include "llapp.h" // For isExiting()
- #include "llcallbacklist.h"
- #include "llbutton.h"
- #include "llcheckboxctrl.h"
- #include "llcombobox.h"
- #include "lldate.h"
- #include "lldir.h"
- #include "lldiriterator.h"
- #include "lllineeditor.h"
- #include "llscrolllistctrl.h"
- #include "llsdserialize.h"
- #include "llstring.h"
- #include "lltextbox.h"
- #include "lluictrlfactory.h"
- // Position in a path string where the root delimiter is found, i.e. position
- // of "\" in (e.g.) "C:\" for Windows and position of "/" (0) for other OSes
- #if LL_WINDOWS
- # define ROOT_DELIMITER_POS 2
- #else
- # define ROOT_DELIMITER_POS 0
- #endif
- // Static variables
- HBFileSelector* HBFileSelector::sInstance = NULL;
- HBFileSelector::context_map_t HBFileSelector::sContextToPathMap;
- std::string HBFileSelector::sLastPath;
- HBFileSelector::HBFileSelector(ELoadFilter filter,
- HBLoadFileCallback callback, void* user_data)
- : mLoadFilter(filter),
- mSaveFilter(FFSAVE_NONE),
- mMultiple(false),
- mSavePicker(false),
- mDirPicker(false),
- mLoadFileCallback(callback),
- mLoadFilesCallback(NULL),
- mSaveFileCallback(NULL),
- mDirPickCallback(NULL)
- {
- init(user_data);
- }
- HBFileSelector::HBFileSelector(ELoadFilter filter,
- HBLoadFilesCallback callback, void* user_data)
- : mLoadFilter(filter),
- mSaveFilter(FFSAVE_NONE),
- mMultiple(true),
- mSavePicker(false),
- mDirPicker(false),
- mLoadFileCallback(NULL),
- mLoadFilesCallback(callback),
- mSaveFileCallback(NULL),
- mDirPickCallback(NULL)
- {
- init(user_data);
- }
- HBFileSelector::HBFileSelector(ESaveFilter filter, std::string& suggestion,
- HBSaveFileCallback callback, void* user_data)
- : mLoadFilter(FFLOAD_NONE),
- mSaveFilter(filter),
- mMultiple(false),
- mSavePicker(true),
- mDirPicker(false),
- mLoadFileCallback(NULL),
- mLoadFilesCallback(NULL),
- mSaveFileCallback(callback),
- mDirPickCallback(NULL),
- mCurrentEntry(suggestion)
- {
- init(user_data);
- }
- HBFileSelector::HBFileSelector(std::string& suggestion,
- HBDirPickCallback callback, void* user_data)
- : mLoadFilter(FFLOAD_NONE),
- mSaveFilter(FFSAVE_NONE),
- mMultiple(false),
- mSavePicker(false),
- mDirPicker(true),
- mLoadFileCallback(NULL),
- mLoadFilesCallback(NULL),
- mSaveFileCallback(NULL),
- mDirPickCallback(callback),
- mCurrentEntry(suggestion)
- {
- init(user_data);
- }
- void HBFileSelector::init(void* user_data)
- {
- sInstance = this;
- mCallbackUserData = user_data;
- mCallbackDone = mIsDirty = mCreatingDirectory = false;
- mContext = CONTEXT_UNKNOWN;
- std::string xui_file = mDirPicker ? "floater_dirselector.xml"
- : "floater_fileselector.xml";
- LLUICtrlFactory::getInstance()->buildFloater(this, xui_file);
- }
- HBFileSelector::~HBFileSelector()
- {
- if (!mCallbackDone && !LLApp::isExiting())
- {
- mCurrentSelection.clear();
- mFiles.clear();
- doCallback();
- }
- sInstance = NULL;
- }
- bool HBFileSelector::postBuild()
- {
- mDirectoriesList = getChild<LLScrollListCtrl>("directories");
- if (mDirPicker)
- {
- mDirectoriesList->setCommitOnSelectionChange(true);
- mDirectoriesList->setCommitCallback(onSelectDirectory);
- }
- mDirectoriesList->setDoubleClickCallback(onLevelDown);
- mDirectoriesList->setCallbackUserData(this);
- if (mDirPicker)
- {
- mFilesList = NULL;
- mShowAllTypesCheck = NULL;
- }
- else
- {
- mFilesList = getChild<LLScrollListCtrl>("files");
- mFilesList->setAllowMultipleSelection(mMultiple);
- mFilesList->setCommitOnSelectionChange(true);
- mFilesList->setCommitCallback(onSelectFile);
- mFilesList->setDoubleClickCallback(onButtonOK);
- mFilesList->setCallbackUserData(this);
- mShowAllTypesCheck = getChild<LLCheckBoxCtrl>("all_files");
- mShowAllTypesCheck->setCommitCallback(onCommitCheckBox);
- mShowAllTypesCheck->setCallbackUserData(this);
- setValidExtensions();
- }
- mPromptTextBox = getChild<LLTextBox>("prompt");
- mPathTextBox = getChild<LLTextBox>("path");
- mInputLine = getChild<LLLineEditor>("selection");
- mInputLine->setOnHandleKeyCallback(onHandleKeyCallback, this);
- mInputLine->setKeystrokeCallback(onKeystrokeCallback);
- mInputLine->setCallbackUserData(this);
- mInputLine->setEnabled(mSavePicker);
- mShowHiddenCheck = getChild<LLCheckBoxCtrl>("show_hidden");
- mShowHiddenCheck->setCommitCallback(onCommitCheckBox);
- mShowHiddenCheck->setCallbackUserData(this);
- mDirLevelFlyoutBtn = getChild<LLFlyoutButton>("dir_level");
- mDirLevelFlyoutBtn->setCommitCallback(onButtonDirLevel);
- mDirLevelFlyoutBtn->setCallbackUserData(this);
- mCreateBtn = getChild<LLButton>("create");
- mCreateBtn->setClickedCallback(onButtonCreate, this);
- mCreateBtn->setEnabled(mSavePicker || mDirPicker);
- mRefreshBtn = getChild<LLButton>("refresh");
- mRefreshBtn->setClickedCallback(onButtonRefresh, this);
- mCancelBtn = getChild<LLButton>("cancel");
- mCancelBtn->setClickedCallback(onButtonCancel, this);
- mOKBtn = getChild<LLButton>("ok");
- mOKBtn->setClickedCallback(onButtonOK, this);
- setPathFromContext();
- setPrompt();
- mIsDirty = true;
- return true;
- }
- void HBFileSelector::draw()
- {
- if (mIsDirty)
- {
- mPathTextBox->setText(mCurrentPath);
- mDirectoriesList->deleteAllItems();
- if (mFilesList)
- {
- mFilesList->deleteAllItems();
- }
- std::string timeformat;
- if (LLUI::sConfigGroup)
- {
- timeformat = LLUI::sConfigGroup->getString("ShortDateFormat") +
- " " +
- LLUI::sConfigGroup->getString("LongTimeFormat");
- }
- #if !LL_WINDOWS
- std::string path = mCurrentPath + LL_DIR_DELIM_STR;
- #else
- std::string path;
- if (!mCurrentPath.empty())
- {
- path = mCurrentPath + LL_DIR_DELIM_STR;
- }
- #endif
- std::string filename;
- LLSD element;
- LLUUID id, selected_id;
- bool selection_is_dir = false;
- #if !LL_WINDOWS
- if (!mCurrentEntry.empty() && mCurrentEntry[0] == '.')
- {
- mShowHiddenCheck->set(true);
- }
- #endif
- bool with_hidden = mShowHiddenCheck->get();
- LLDirIterator iter(path, NULL, DI_ALL);
- while (iter.next(filename))
- {
- if (!with_hidden && iter.isHidden())
- {
- continue; // Do not list hidden entries
- }
- bool is_dir = iter.isDirectory();
- element.clear();
- id.generate();
- if (filename == mCurrentEntry)
- {
- selected_id = id;
- selection_is_dir = is_dir;
- }
- element["id"] = id;
- if (is_dir)
- {
- element["columns"][0]["column"] = "dirname_col";
- element["columns"][0]["value"] = filename;
- if (iter.isLink())
- {
- element["columns"][0]["font-style"] = "ITALIC";
- }
- mDirectoriesList->addElement(element, ADD_SORTED);
- }
- else if (mFilesList && isFileExtensionValid(filename))
- {
- element["columns"][0]["column"] = "name_col";
- element["columns"][0]["value"] = filename;
- if (iter.isLink())
- {
- element["columns"][0]["font-style"] = "ITALIC";
- }
- element["columns"][1]["column"] = "size_col";
- element["columns"][1]["value"] = (LLSD::Integer)iter.getSize();
- element["columns"][2]["column"] = "date_col";
- element["columns"][2]["type"] = "date";
- element["columns"][2]["format"] = timeformat;
- element["columns"][2]["value"] = LLDate(iter.getTimeStamp());
- mFilesList->addElement(element, ADD_SORTED);
- }
- }
- // Set the current selection, if any:
- if (mCurrentEntry.empty())
- {
- mInputLine->clear();
- }
- else
- {
- mInputLine->setText(mCurrentEntry);
- mInputLine->setCursorToEnd();
- bool got_it = mSavePicker;
- if (selected_id.notNull())
- {
- if (selection_is_dir)
- {
- if (mDirPicker &&
- mDirectoriesList->selectByID(selected_id))
- {
- mDirectoriesList->scrollToShowSelected();
- got_it = true;
- }
- }
- else if (mFilesList && mFilesList->selectByID(selected_id))
- {
- mFilesList->scrollToShowSelected();
- got_it = true;
- }
- }
- if (!got_it)
- {
- mCurrentEntry.clear();
- }
- }
- mIsDirty = false;
- }
- LLFloater::draw();
- }
- void HBFileSelector::setValidExtensions()
- {
- mContext = CONTEXT_DEFAULT;
- mValidExtensions.clear();
- if (mSavePicker)
- {
- mFileTypeDescription = getString("any_file") + " (*.*)";
- }
- else if (!mDirPicker)
- {
- mFileTypeDescription = getString("all_files") + " (*.*)";
- }
- if (!mShowAllTypesCheck || mShowAllTypesCheck->get())
- {
- return;
- }
- if (mSavePicker && mSaveFilter != FFSAVE_NONE && mSaveFilter != FFSAVE_ALL)
- {
- switch (mSaveFilter)
- {
- case FFSAVE_TXT:
- mValidExtensions.emplace_back("txt");
- mFileTypeDescription = getString("txt_file") + " (*.txt)";
- mContext = CONTEXT_TXT;
- break;
- case FFSAVE_XML:
- mValidExtensions.emplace_back("xml");
- mFileTypeDescription = getString("xml_file") + " (*.xml)";
- mContext = CONTEXT_XML;
- break;
- case FFSAVE_XUI:
- mValidExtensions.emplace_back("xml");
- mFileTypeDescription = getString("xui_file") + " (*.xml)";
- mContext = CONTEXT_XUI;
- break;
- case FFSAVE_LSL:
- mValidExtensions.emplace_back("lsl");
- mFileTypeDescription = getString("lsl_file") + " (*.lsl)";
- mContext = CONTEXT_LSL;
- break;
- case FFSAVE_WAV:
- mValidExtensions.emplace_back("wav");
- mFileTypeDescription = getString("wav_file") + " (*.wav)";
- mContext = CONTEXT_SOUND;
- break;
- case FFSAVE_BVH:
- mValidExtensions.emplace_back("bvh");
- mFileTypeDescription = getString("bvh_file") + " (*.bvh)";
- mContext = CONTEXT_ANIM;
- break;
- case FFSAVE_DAE:
- mValidExtensions.emplace_back("dae");
- mFileTypeDescription = getString("dae_file") + " (*.dae)";
- mContext = CONTEXT_MODEL;
- break;
- case FFSAVE_OBJ:
- mValidExtensions.emplace_back("obj");
- mFileTypeDescription = getString("obj_file") + " (*.obj)";
- mContext = CONTEXT_MODEL;
- break;
- case FFSAVE_RAW:
- mValidExtensions.emplace_back("raw");
- mFileTypeDescription = getString("raw_file") + " (*.raw)";
- mContext = CONTEXT_RAW;
- break;
- case FFSAVE_TGA:
- mValidExtensions.emplace_back("tga");
- mFileTypeDescription = getString("tga_file") + " (*.tga)";
- mContext = CONTEXT_IMAGE;
- break;
- case FFSAVE_PNG:
- mValidExtensions.emplace_back("png");
- mFileTypeDescription = getString("png_file") + " (*.png)";
- mContext = CONTEXT_IMAGE;
- break;
- case FFSAVE_JPG:
- mValidExtensions.emplace_back("jpg");
- mFileTypeDescription = getString("jpg_file") +
- " (*.jpg;*.jpeg)";
- mContext = CONTEXT_IMAGE;
- break;
- case FFSAVE_J2C:
- mValidExtensions.emplace_back("j2c");
- mFileTypeDescription = getString("j2c_file") + " (*.j2c)";
- mContext = CONTEXT_IMAGE;
- break;
- case FFSAVE_BMP:
- mValidExtensions.emplace_back("bmp");
- mFileTypeDescription = getString("bmp_file") + " (*.bmp)";
- mContext = CONTEXT_IMAGE;
- break;
- case FFSAVE_GLTF:
- mValidExtensions.emplace_back("glb");
- mFileTypeDescription = getString("gltf_file") + " (*.glb)";
- mContext = CONTEXT_MATERIAL;
- break;
- default:
- break;
- }
- }
- else if (mLoadFilter != FFLOAD_NONE && mLoadFilter != FFLOAD_ALL)
- {
- switch (mLoadFilter)
- {
- case FFLOAD_TEXT:
- mValidExtensions.emplace_back("txt");
- mFileTypeDescription = getString("text_files") + " (*.txt)";
- mContext = CONTEXT_TXT;
- break;
- case FFLOAD_XML:
- mValidExtensions.emplace_back("xml");
- mFileTypeDescription = getString("xml_files") + " (*.xml)";
- mContext = CONTEXT_XML;
- break;
- case FFLOAD_XUI:
- mValidExtensions.emplace_back("xml");
- mFileTypeDescription = getString("xui_files") + " (*.xml)";
- mContext = CONTEXT_XUI;
- break;
- case FFLOAD_SCRIPT:
- mValidExtensions.emplace_back("lsl");
- mFileTypeDescription = getString("script_files") + " (*.lsl)";
- mContext = CONTEXT_LSL;
- break;
- case FFLOAD_SOUND:
- mValidExtensions.emplace_back("wav");
- mValidExtensions.emplace_back("dsf");
- mFileTypeDescription = getString("sound_files") +
- " (*.wav;*.dsf)";
- mContext = CONTEXT_SOUND;
- break;
- case FFLOAD_ANIM:
- mValidExtensions.emplace_back("bvh");
- mValidExtensions.emplace_back("anim");
- mFileTypeDescription = getString("animation_files") +
- " (*.bvh;*.anim)";
- mContext = CONTEXT_ANIM;
- break;
- case FFLOAD_MODEL:
- mValidExtensions.emplace_back("dae");
- mValidExtensions.emplace_back("glb");
- mValidExtensions.emplace_back("gltf");
- mFileTypeDescription = getString("model_files") +
- " (*.dae;*.glb;*.gltf)";
- mContext = CONTEXT_MODEL;
- break;
- case FFLOAD_TERRAIN:
- mValidExtensions.emplace_back("raw");
- mFileTypeDescription = getString("raw_files") + " (*.raw)";
- mContext = CONTEXT_RAW;
- break;
- case FFLOAD_IMAGE:
- mValidExtensions.emplace_back("tga");
- mValidExtensions.emplace_back("png");
- mValidExtensions.emplace_back("jpg");
- mValidExtensions.emplace_back("jpeg");
- mValidExtensions.emplace_back("bmp");
- mFileTypeDescription = getString("image_files") +
- " (*.tga;*.png;*.jpg;*.jpeg;*.bmp)";
- mContext = CONTEXT_IMAGE;
- break;
- case FFLOAD_HDRI:
- mValidExtensions.emplace_back("exr");
- mFileTypeDescription = getString("exr_file") + " (*.exr)";
- mContext = CONTEXT_IMAGE;
- break;
- case FFLOAD_LUA:
- mValidExtensions.emplace_back("lua");
- mValidExtensions.emplace_back("luac");
- mFileTypeDescription = getString("lua_files") +
- " (*.lua;*.luac)";
- mContext = CONTEXT_LUA;
- break;
- case FFLOAD_GLTF:
- mValidExtensions.emplace_back("glb");
- mValidExtensions.emplace_back("gltf");
- mFileTypeDescription = getString("gltf_files") +
- " (*.glb;*.gltf)";
- mContext = CONTEXT_MATERIAL;
- break;
- default:
- break;
- }
- }
- }
- void HBFileSelector::setPrompt()
- {
- std::string prompt;
- bool got_file_info = !mFileTypeDescription.empty();
- if (mCreatingDirectory)
- {
- prompt = getString("new_directory");
- }
- else if (mSavePicker && got_file_info)
- {
- prompt = getString("prompt_save") + " " + mFileTypeDescription;
- }
- else if (mMultiple && got_file_info)
- {
- prompt = getString("prompt_load_multiple") + " " +
- mFileTypeDescription;
- }
- else if (!mMultiple && !mSavePicker && got_file_info)
- {
- prompt = getString("prompt_load_one") + " " + mFileTypeDescription;
- }
- else
- {
- prompt = getString("default_prompt");
- }
- mPromptTextBox->setText(prompt);
- if (mSaveFilter == FFSAVE_NONE)
- {
- mPromptTextBox->setColor(LLColor4::green);
- }
- else
- {
- mPromptTextBox->setColor(LLColor4::yellow);
- }
- }
- bool HBFileSelector::isFileExtensionValid(const std::string& filename)
- {
- if (mValidExtensions.empty() ||
- (mShowAllTypesCheck && mShowAllTypesCheck->get()))
- {
- return true;
- }
- std::string tmp = filename;
- LLStringUtil::toLower(tmp);
- size_t j = tmp.rfind('.');
- if (j == std::string::npos || j == tmp.length() - 1)
- {
- return false;
- }
- tmp = tmp.substr(j + 1);
- for (U32 i = 0, count = mValidExtensions.size(); i < count; ++i)
- {
- if (mValidExtensions[i] == tmp)
- {
- return true;
- }
- }
- return false;
- }
- void HBFileSelector::setPathFromContext()
- {
- if (mDirPicker)
- {
- std::string tmp = mCurrentEntry;
- if (!tmp.empty())
- {
- // Remove trailing delimiter(s)
- while (tmp.length() &&
- tmp.rfind(LL_DIR_DELIM_CHR) == tmp.length() - 1)
- {
- tmp = tmp.substr(0, tmp.length() - 1);
- }
- size_t i = tmp.rfind(LL_DIR_DELIM_CHR);
- if (i != std::string::npos && i >= 1)
- {
- // Suggested directory selection
- mCurrentEntry = tmp.substr(i + 1);
- // Parent directory path
- mCurrentPath = tmp.substr(0, i);
- }
- else
- {
- // Suggested directory selection = root directory
- mCurrentEntry = tmp;
- mCurrentPath.clear();
- }
- }
- else
- {
- mCurrentPath = sLastPath;
- }
- }
- else
- {
- context_map_t::iterator it = sContextToPathMap.find(mContext);
- if (it != sContextToPathMap.end())
- {
- mCurrentPath = it->second;
- }
- else
- {
- mCurrentPath.clear();
- }
- // If the saved path is not valid any more, try to find the deepest
- // directory that used to contain it...
- while (!mCurrentPath.empty() && !LLFile::exists(mCurrentPath))
- {
- size_t i = mCurrentPath.rfind(LL_DIR_DELIM_CHR);
- if (i == std::string::npos || i == ROOT_DELIMITER_POS)
- {
- mCurrentPath.clear();
- break;
- }
- mCurrentPath.erase(i);
- }
- if (mCurrentPath.empty())
- {
- if (mContext == CONTEXT_XUI)
- {
- #define XUI_DIR LL_DIR_DELIM_STR "xui" LL_DIR_DELIM_STR "en-us"
- mCurrentPath = gDirUtil.getSkinDir() + XUI_DIR;
- }
- else
- {
- mCurrentPath = sLastPath;
- }
- }
- }
- if (mCurrentPath.empty() || !LLFile::exists(mCurrentPath))
- {
- if (!sLastPath.empty() && LLFile::exists(sLastPath))
- {
- mCurrentPath = sLastPath;
- }
- else
- {
- mCurrentPath = gDirUtil.getOSUserDir();
- }
- }
- isCurrentPathAtRoot();
- }
- bool HBFileSelector::isCurrentPathAtRoot()
- {
- // Remove trailing delimiter(s)
- mCurrentPath.erase(mCurrentPath.find_last_not_of(LL_DIR_DELIM_CHR) + 1);
- return mCurrentPath.empty();
- }
- void HBFileSelector::setSelectionData()
- {
- mFiles.clear();
- #if !LL_WINDOWS
- std::string path = mCurrentPath + LL_DIR_DELIM_STR;
- #else
- std::string path;
- if (!mCurrentPath.empty())
- {
- path = mCurrentPath + LL_DIR_DELIM_STR;
- }
- #endif
- std::string filename;
- LLScrollListItem* item = NULL;
- if (mDirPicker)
- {
- item = mDirectoriesList->getFirstSelected();
- }
- else if (mFilesList)
- {
- if (mMultiple)
- {
- std::vector<LLScrollListItem*> items;
- items = mFilesList->getAllSelected();
- if (!items.empty())
- {
- for (std::vector<LLScrollListItem*>::const_iterator
- iter = items.begin(), end = items.end();
- iter != end; ++iter)
- {
- item = *iter;
- if (item && item->getColumn(0))
- {
- filename = item->getColumn(0)->getValue().asString();
- mFiles.emplace_back(path + filename);
- }
- }
- }
- }
- item = mFilesList->getFirstSelected();
- }
- if (item && item->getColumn(0))
- {
- filename = item->getColumn(0)->getValue().asString();
- mCurrentSelection = path + filename;
- mInputLine->setText(filename);
- }
- else if ((mDirPicker || mSavePicker) && !mInputLine->getText().empty())
- {
- mCurrentSelection = path + mInputLine->getText();
- }
- }
- void HBFileSelector::doCallback()
- {
- if (!mCallbackDone)
- {
- mCallbackDone = true;
- if (mLoadFileCallback)
- {
- mLoadFileCallback(mLoadFilter, mCurrentSelection,
- mCallbackUserData);
- }
- else if (mLoadFilesCallback)
- {
- mLoadFilesCallback(mLoadFilter, mFiles, mCallbackUserData);
- }
- else if (mSaveFileCallback)
- {
- if (!mCurrentSelection.empty() &&
- !isFileExtensionValid(mCurrentSelection))
- {
- mCurrentSelection += "." + mValidExtensions[0];
- }
- mSaveFileCallback(mSaveFilter, mCurrentSelection,
- mCallbackUserData);
- }
- else if (mDirPickCallback)
- {
- mDirPickCallback(mCurrentSelection, mCallbackUserData);
- }
- }
- }
- //static
- void HBFileSelector::loadFile(ELoadFilter filter,
- HBLoadFileCallback callback, void* user_data)
- {
- if (sInstance)
- {
- llwarns << "Call done while a file selector instance already exists ! Aborting."
- << llendl;
- llassert(false);
- }
- else
- {
- new HBFileSelector(filter, callback, user_data);
- }
- }
- //static
- void HBFileSelector::loadFiles(ELoadFilter filter,
- HBLoadFilesCallback callback, void* user_data)
- {
- if (sInstance)
- {
- llwarns << "Call done while a file selector instance already exists ! Aborting."
- << llendl;
- llassert(false);
- }
- else
- {
- new HBFileSelector(filter, callback, user_data);
- }
- }
- //static
- void HBFileSelector::saveFile(ESaveFilter filter, std::string suggestion,
- HBSaveFileCallback callback, void* user_data)
- {
- if (sInstance)
- {
- llwarns << "Call done while a file selector instance already exists ! Aborting."
- << llendl;
- llassert(false);
- }
- else
- {
- new HBFileSelector(filter, suggestion, callback, user_data);
- }
- }
- //static
- void HBFileSelector::pickDirectory(std::string suggestion,
- HBDirPickCallback callback, void* user_data)
- {
- if (sInstance)
- {
- llwarns << "Call done while a file selector instance already exists ! Aborting."
- << llendl;
- llassert(false);
- }
- else
- {
- new HBFileSelector(suggestion, callback, user_data);
- }
- }
- //static
- void HBFileSelector::onButtonRefresh(void* user_data)
- {
- HBFileSelector* self = (HBFileSelector*)user_data;
- if (self)
- {
- if (self->mSavePicker && !self->mInputLine->getText().empty())
- {
- self->mCurrentEntry = self->mInputLine->getText();
- }
- self->mIsDirty = true;
- }
- }
- //static
- void HBFileSelector::onButtonDirLevel(LLUICtrl* ctrl, void* user_data)
- {
- HBFileSelector* self = (HBFileSelector*)user_data;
- if (self && ctrl)
- {
- if (self->mDirPicker)
- {
- self->mCurrentEntry.clear();
- }
- std::string operation = ctrl->getValue().asString();
- if (operation == "home")
- {
- self->mCurrentPath = gDirUtil.getOSUserDir();
- self->isCurrentPathAtRoot();
- self->mIsDirty = true;
- }
- else if (operation == "suggested")
- {
- // *TODO: implement for directory selector as well ?
- if (!self->mDirPicker)
- {
- self->setPathFromContext();
- self->mIsDirty = true;
- }
- }
- else if (operation == "last")
- {
- if (!sLastPath.empty() && LLFile::exists(sLastPath))
- {
- self->mCurrentPath = sLastPath;
- self->mIsDirty = true;
- }
- }
- else if (operation == "root")
- {
- if (!self->isCurrentPathAtRoot())
- {
- #if LL_WINDOWS
- self->mCurrentPath.clear();
- #else
- self->mCurrentPath = LL_DIR_DELIM_STR;
- #endif
- self->isCurrentPathAtRoot();
- self->mIsDirty = true;
- }
- }
- else if (!self->isCurrentPathAtRoot())
- {
- // "level_up" operation
- size_t i = self->mCurrentPath.rfind(LL_DIR_DELIM_CHR);
- if (i != std::string::npos)
- {
- self->mCurrentPath = self->mCurrentPath.substr(0, i);
- self->mIsDirty = true;
- }
- #if LL_WINDOWS
- else
- {
- self->mCurrentPath.clear();
- self->mIsDirty = true;
- }
- #endif
- self->isCurrentPathAtRoot();
- }
- }
- }
- //static
- void HBFileSelector::onButtonCreate(void* user_data)
- {
- HBFileSelector* self = (HBFileSelector*)user_data;
- if (self)
- {
- std::string entry = self->mInputLine->getText();
- if (!entry.empty())
- {
- self->mInputLine->clear();
- self->mCurrentEntry = entry;
- }
- self->mInputLine->setEnabled(true);
- self->mCreatingDirectory = true;
- self->mDirLevelFlyoutBtn->setEnabled(false);
- self->mCreateBtn->setEnabled(false);
- self->mRefreshBtn->setEnabled(false);
- self->mOKBtn->setEnabled(false);
- self->mShowHiddenCheck->setEnabled(false);
- if (self->mShowAllTypesCheck)
- {
- self->mShowAllTypesCheck->setEnabled(false);
- }
- self->mDirectoriesList->setEnabled(false);
- if (self->mFilesList)
- {
- self->mFilesList->setEnabled(false);
- }
- self->setPrompt();
- }
- }
- static void close_selector(HBFileSelector* floaterp)
- {
- floaterp->close();
- }
- //static
- void HBFileSelector::onButtonOK(void* user_data)
- {
- HBFileSelector* self = (HBFileSelector*)user_data;
- if (self)
- {
- self->setSelectionData();
- sLastPath = self->mCurrentPath;
- sContextToPathMap[self->mContext] = sLastPath;
- #if LL_WINDOWS
- // If we are at the drive selection level, we cannot return a selection
- if (sLastPath.empty())
- {
- self->mFiles.clear();
- self->mCurrentSelection.clear();
- }
- #endif
- self->doCallback();
- // We cannot close the floater now, because it would mean destroying
- // this instance while this method is also called for keyboard events
- // occurring at a point its member variables would be used later on,
- // causing a crash. So we instead hide the floater (so that nothing any
- // more can be performed using it) and we register a one-shot idle
- // callback to the close_selector() function.
- self->setVisible(false);
- doOnIdleOneTime(boost::bind(&close_selector, self));
- }
- }
- //static
- void HBFileSelector::onButtonCancel(void* user_data)
- {
- HBFileSelector* self = (HBFileSelector*)user_data;
- if (self)
- {
- self->close();
- }
- }
- //static
- void HBFileSelector::onSelectDirectory(LLUICtrl*, void* user_data)
- {
- HBFileSelector* self = (HBFileSelector*)user_data;
- if (self)
- {
- self->mCurrentEntry = self->mInputLine->getText();
- self->setSelectionData();
- }
- }
- //static
- void HBFileSelector::onLevelDown(void* user_data)
- {
- HBFileSelector* self = (HBFileSelector*)user_data;
- if (self && self->mDirectoriesList)
- {
- if (self->mDirPicker)
- {
- self->mCurrentEntry.clear();
- }
- LLScrollListItem* item = self->mDirectoriesList->getFirstSelected();
- if (item && item->getColumn(0))
- {
- #if LL_WINDOWS
- if (!self->mCurrentPath.empty())
- #endif
- {
- self->mCurrentPath += LL_DIR_DELIM_STR;
- }
- self->mCurrentPath += item->getColumn(0)->getValue().asString();
- self->mDirectoriesList->deselectAllItems(true);
- self->isCurrentPathAtRoot();
- self->mIsDirty = true;
- }
- }
- }
- //static
- void HBFileSelector::onSelectFile(LLUICtrl*, void* user_data)
- {
- HBFileSelector* self = (HBFileSelector*)user_data;
- if (self)
- {
- self->mCurrentEntry = self->mInputLine->getText();
- self->setSelectionData();
- }
- }
- //static
- void HBFileSelector::onCommitCheckBox(LLUICtrl*, void* user_data)
- {
- HBFileSelector* self = (HBFileSelector*)user_data;
- if (self)
- {
- self->mIsDirty = true;
- }
- }
- //static
- bool HBFileSelector::onHandleKeyCallback(KEY key, MASK mask,
- LLLineEditor* caller, void* user_data)
- {
- bool handled = false;
- HBFileSelector* self = (HBFileSelector*)user_data;
- if (self && key == KEY_RETURN && mask == MASK_NONE)
- {
- if (self->mCreatingDirectory)
- {
- self->mCreatingDirectory = false;
- std::string new_dir = self->mInputLine->getText();
- if (!new_dir.empty())
- {
- std::string dir_name = self->mInputLine->getText();
- std::string new_dir = self->mCurrentPath + LL_DIR_DELIM_STR +
- dir_name;
- LLFile::mkdir(new_dir);
- if (LLFile::isdir(new_dir))
- {
- if (self->mDirPicker)
- {
- // Adopt the new directory as the current entry
- self->mCurrentEntry = dir_name;
- }
- else
- {
- // Change to the newly created directory
- self->mCurrentPath = new_dir;
- self->mDirectoriesList->deselectAllItems(true);
- self->isCurrentPathAtRoot();
- // Restore file suggestion, if any
- self->mInputLine->setText(self->mCurrentEntry);
- }
- }
- }
- if (!self->mSavePicker)
- {
- self->mInputLine->setEnabled(false);
- }
- self->mDirLevelFlyoutBtn->setEnabled(true);
- self->mCreateBtn->setEnabled(true);
- self->mRefreshBtn->setEnabled(true);
- self->mOKBtn->setEnabled(true);
- self->mShowHiddenCheck->setEnabled(true);
- if (self->mShowAllTypesCheck)
- {
- self->mShowAllTypesCheck->setEnabled(true);
- }
- self->mDirectoriesList->setEnabled(true);
- if (self->mFilesList)
- {
- self->mFilesList->setEnabled(true);
- }
- self->setPrompt();
- self->mIsDirty = true;
- handled = true;
- }
- else if (self->mSavePicker)
- {
- self->setSelectionData();
- onButtonOK(self);
- handled = true;
- }
- }
- return handled;
- }
- //static
- void HBFileSelector::onKeystrokeCallback(LLLineEditor* caller, void* user_data)
- {
- HBFileSelector* self = (HBFileSelector*)user_data;
- if (self && caller && caller->getEnabled())
- {
- // We must deselect any selected entry if we just typed a new letter,
- // else the selected entry would override what the user entered in the
- // input line whenever a suggested file/dir name corresponds to an
- // existing file/dir...
- if (self->mDirPicker)
- {
- self->mDirectoriesList->deselectAllItems();
- }
- else if (self->mSavePicker && !self->mCreatingDirectory)
- {
- self->mFilesList->deselectAllItems();
- }
- }
- }
- //static
- void HBFileSelector::saveDefaultPaths(const std::string& filename)
- {
- std::string fullpath = gDirUtil.getFullPath(LL_PATH_USER_SETTINGS,
- filename);
- llofstream out(fullpath.c_str());
- if (!out.is_open())
- {
- llwarns << "Unable to open \"" << fullpath
- << "\" for writing. Default paths not saved." << llendl;
- return;
- }
- llinfos << "Saving default selector paths to: " << fullpath << llendl;
- LLSD data;
- context_map_t::iterator end = sContextToPathMap.end();
- for (S32 context = CONTEXT_DEFAULT; context < CONTEXT_END; ++context)
- {
- std::string path;
- context_map_t::iterator it = sContextToPathMap.find(context);
- if (it != end)
- {
- path = it->second;
- }
- data.set(context, path);
- }
- LLSDSerialize::toPrettyXML(data, out);
- out.close();
- }
- //static
- void HBFileSelector::loadDefaultPaths(const std::string& filename)
- {
- std::string fullpath = gDirUtil.getFullPath(LL_PATH_USER_SETTINGS,
- filename);
- LLSD data;
- llifstream input(fullpath.c_str());
- if (input.is_open())
- {
- llinfos << "Loading default selector paths from: " << fullpath
- << llendl;
- LLSDSerialize::fromXML(data, input);
- }
- if (data.isUndefined() || !data.isArray())
- {
- llinfos << "Default selector paths file \"" << fullpath
- << "\" is missing, ill-formed, or simply undefined." << llendl;
- return;
- }
- for (S32 context = CONTEXT_DEFAULT; context < CONTEXT_END; ++context)
- {
- std::string path = data.get(context).asString();
- if (!path.empty())
- {
- sContextToPathMap.emplace(context, path);
- }
- }
- input.close();
- }
|