diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 2eaf6c580..b67d4b085 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -9,6 +9,18 @@ settings_rlv.xml + TeleportHistoryMaxEntries + + Comment + Maximum number of entries to allow in teleport history list. + Persist + 1 + Type + S32 + Value + 100 + + AllowLargeSounds Comment diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index cf0da0c48..53f5e4229 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -79,6 +79,7 @@ #include "llrender.h" #include "llfont.h" #include "llvocache.h" +#include "llfloaterteleporthistory.h" #include "llweb.h" #include "llsecondlifeurls.h" @@ -1450,6 +1451,8 @@ bool LLAppViewer::cleanup() // Save file- and dirpicker {context, default paths} map. AIFilePicker::saveFile("filepicker_contexts.xml"); + LLFloaterTeleportHistory::saveFile("teleport_history.xml"); + // save mute list. gMuteList used to also be deleted here too. LLMuteList::getInstance()->cache(gAgent.getID()); diff --git a/indra/newview/llfloaterteleporthistory.cpp b/indra/newview/llfloaterteleporthistory.cpp index 41d4b091d..f32fa55be 100644 --- a/indra/newview/llfloaterteleporthistory.cpp +++ b/indra/newview/llfloaterteleporthistory.cpp @@ -49,11 +49,9 @@ #include "llviewercontrol.h" #include "llviewerwindow.h" #include "llweb.h" +#include "llsdserialize.h" -// globals -LLFloaterTeleportHistory* gFloaterTeleportHistory; - -LLFloaterTeleportHistory::LLFloaterTeleportHistory() +LLFloaterTeleportHistory::LLFloaterTeleportHistory(const LLSD& seed) : LLFloater(std::string("teleporthistory")), mPlacesList(NULL), mID(0) @@ -171,10 +169,18 @@ void LLFloaterTeleportHistory::addEntry(std::string parcelName) value["columns"][LIST_SIMSTRING]["value"] = mPendingSimString; // add the new list entry on top of the list, deselect all and disable the buttons + const S32 max_entries = gSavedSettings.getS32("TeleportHistoryMaxEntries"); + S32 num_entries = mPlacesList->getItemCount(); + while(num_entries >= max_entries) + { + mPlacesList->deleteItems(LLSD(mID - num_entries--)); + } + mPlacesList->addElement(value, ADD_TOP); mPlacesList->deselectAllItems(TRUE); setButtonsEnabled(FALSE); mID++; + saveFile("teleport_history.xml"); //Comment out to disable saving after every teleport. } else { @@ -191,6 +197,95 @@ void LLFloaterTeleportHistory::setButtonsEnabled(BOOL on) childSetEnabled("show_on_map", on); childSetEnabled("copy_slurl", on); } +//static +void LLFloaterTeleportHistory::loadFile(const std::string &file_name) +{ + LLFloaterTeleportHistory *pFloaterHistory = LLFloaterTeleportHistory::findInstance(); + if(!pFloaterHistory) + return; + + LLScrollListCtrl* pScrollList = pFloaterHistory->mPlacesList; + if(!pScrollList) + return; + + std::string temp_str(gDirUtilp->getLindenUserDir() + gDirUtilp->getDirDelimiter() + file_name); + + llifstream file(temp_str); + + if (file.is_open()) + { + llinfos << "Loading "<< file_name << " file at " << temp_str << llendl; + LLSD data; + LLSDSerialize::fromXML(data, file); + if (data.isUndefined()) + { + llinfos << "file missing, ill-formed, " + "or simply undefined; not reading the" + " file" << llendl; + } + else + { + const S32 max_entries = gSavedSettings.getS32("TeleportHistoryMaxEntries"); + const S32 num_entries = llmin(max_entries,(const S32)data.size()); + pScrollList->clear(); + for(S32 i = 0; i < num_entries; i++) //Lower entry = newer + { + pScrollList->addElement(data[i], ADD_BOTTOM); + } + pScrollList->deselectAllItems(TRUE); + pFloaterHistory->mID = pScrollList->getItemCount(); + pFloaterHistory->setButtonsEnabled(FALSE); + } + } +} +//static +void LLFloaterTeleportHistory::saveFile(const std::string &file_name) +{ + LLFloaterTeleportHistory *pFloaterHistory = LLFloaterTeleportHistory::findInstance(); + if(!pFloaterHistory) + return; + + std::string temp_str = gDirUtilp->getLindenUserDir(true); + if( temp_str.empty() ) + { + llinfos << "Can't save teleport history - no user directory set yet." << llendl; + return; + } + temp_str += gDirUtilp->getDirDelimiter() + file_name; + llofstream export_file(temp_str); + if (!export_file.good()) + { + llwarns << "Unable to open " << file_name << " for output." << llendl; + return; + } + llinfos << "Writing "<< file_name << " file at " << temp_str << llendl; + + LLSD elements; + LLScrollListCtrl* pScrollList = pFloaterHistory->mPlacesList; + if (pScrollList) + { + std::vector data_list = pScrollList->getAllData(); + struct SortByAge { + bool operator() (LLScrollListItem* i,LLScrollListItem* j) { return (i->getValue().asInteger()>j->getValue().asInteger());} + } sorter; + std::sort(data_list.begin(),data_list.end(),sorter);//Re-sort. Column sorting may have mucked the list up. Newer entries in front. + for (std::vector::iterator itr = data_list.begin(); itr != data_list.end(); ++itr) + { + //Pack into LLSD mimicing one passed to addElement + LLSD data_entry; + //id is actually reverse of the indexing of the element LLSD. Higher id = newer. + data_entry["id"] = pScrollList->getItemCount() - elements.size() - 1; + for(S32 i = 0; i < (*itr)->getNumColumns(); ++i) + { + data_entry["columns"][i]["column"]=pScrollList->getColumn(i)->mName; + data_entry["columns"][i]["value"]=(*itr)->getColumn(i)->getValue(); + } + elements.append(data_entry); + } + } + LLSDSerialize::toXML(elements, export_file); + export_file.close(); +} // virtual void LLFloaterTeleportHistory::onClose(bool app_quitting) diff --git a/indra/newview/llfloaterteleporthistory.h b/indra/newview/llfloaterteleporthistory.h index 06e4b75ad..feed44bc5 100644 --- a/indra/newview/llfloaterteleporthistory.h +++ b/indra/newview/llfloaterteleporthistory.h @@ -43,10 +43,10 @@ #include "llfloater.h" #include "llscrolllistctrl.h" -class LLFloaterTeleportHistory : public LLFloater +class LLFloaterTeleportHistory : public LLFloater, public LLUISingleton { public: - LLFloaterTeleportHistory(); + LLFloaterTeleportHistory(const LLSD& seed); virtual ~LLFloaterTeleportHistory(); /// @brief: reimplemented to check for selection changes in the places list scrolllist @@ -65,6 +65,8 @@ public: /// @brief: adds the destination to the list of visited places void addEntry(std::string parcelName); + static void loadFile(const std::string &file_name); + static void saveFile(const std::string &file_name); private: enum HISTORY_COLUMN_ORDER { @@ -93,9 +95,21 @@ private: std::string mPendingSimString; std::string mPendingTimeString; std::string mPendingSLURL; + +public: + // visibility policy for LLUISingleton + static bool visible(LLFloater* instance, const LLSD& key) + { + return VisibilityPolicy::visible(instance, key); + } + static void show(LLFloater* instance, const LLSD& key) + { + VisibilityPolicy::show(instance, key); + } + static void hide(LLFloater* instance, const LLSD& key) + { + VisibilityPolicy::hide(instance, key); + } }; - -// globals -extern LLFloaterTeleportHistory* gFloaterTeleportHistory; - #endif + diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index 09e1abff2..a0c263cf2 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -6393,7 +6393,7 @@ class LLShowFloater : public view_listener_t } else if (floater_name == "teleport history") { - gFloaterTeleportHistory->setVisible(!gFloaterTeleportHistory->getVisible()); + LLFloaterTeleportHistory::toggleInstance(); } else if (floater_name == "im") { @@ -6556,7 +6556,7 @@ class LLFloaterVisible : public view_listener_t } else if (floater_name == "teleport history") { - new_value = (gFloaterTeleportHistory && gFloaterTeleportHistory->getVisible()); + new_value = LLFloaterTeleportHistory::instanceVisible(); } else if (floater_name == "im") { diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index f1529ef58..f35518339 100644 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -3904,7 +3904,7 @@ void process_agent_movement_complete(LLMessageSystem* msg, void**) } // add teleport destination to the list of visited places - gFloaterTeleportHistory->addPendingEntry(regionp->getName(), (S16)agent_pos.mV[VX], (S16)agent_pos.mV[VY], (S16)agent_pos.mV[VZ]); + LLFloaterTeleportHistory::getInstance()->addPendingEntry(regionp->getName(), (S16)agent_pos.mV[VX], (S16)agent_pos.mV[VY], (S16)agent_pos.mV[VZ]); } else { diff --git a/indra/newview/llviewerparcelmgr.cpp b/indra/newview/llviewerparcelmgr.cpp index b84e00b10..e68223285 100644 --- a/indra/newview/llviewerparcelmgr.cpp +++ b/indra/newview/llviewerparcelmgr.cpp @@ -1546,7 +1546,7 @@ void LLViewerParcelMgr::processParcelProperties(LLMessageSystem *msg, void **use } // Add any pending entry to the TP history now that we got the *new* parcel name. - gFloaterTeleportHistory->addEntry(LLViewerParcelMgr::getInstance()->getAgentParcelName()); + LLFloaterTeleportHistory::getInstance()->addEntry(LLViewerParcelMgr::getInstance()->getAgentParcelName()); // Handle updating selections, if necessary. if (sequence_id == SELECTED_PARCEL_SEQ_ID) diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index 0f5d0ed64..3ba0e0cf7 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -2005,8 +2005,8 @@ void LLViewerWindow::initWorldUI_postLogin() gFloaterWorldMap->setVisible(FALSE); // open teleport history floater and hide it initially - gFloaterTeleportHistory = new LLFloaterTeleportHistory(); - gFloaterTeleportHistory->setVisible(FALSE); + LLFloaterTeleportHistory::getInstance()->setVisible(FALSE); + LLFloaterTeleportHistory::loadFile("teleport_history.xml"); LLFloaterChatterBox::createInstance(LLSD()); }