//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() )
    {
        LL_INFOS() << "Can't save teleport history - no user directory set yet." << LL_ENDL;
        return;
    }
    temp_str += gDirUtilp->getDirDelimiter() + file_name;
    llofstream export_file(temp_str);
    if (!export_file.good())
    {
        LL_WARNS() << "Unable to open " << file_name << " for output." << LL_ENDL;
        return;
    }
    LL_INFOS() << "Writing "<< file_name << " file at " << temp_str << LL_ENDL;

    LLSD elements;
    LLScrollListCtrl* pScrollList = pFloaterHistory->mPlacesList;
    if (pScrollList)
    {
        std::vector<LLScrollListItem*> data_list = pScrollList->getAllData();
        std::sort(data_list.begin(),data_list.end(),SortByAge());//Re-sort. Column sorting may have mucked the list up. Newer entries in front.
        for (std::vector<LLScrollListItem*>::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();
}