diff options
Diffstat (limited to 'indra')
| -rw-r--r-- | indra/newview/llpreviewnotecard.cpp | 166 | ||||
| -rw-r--r-- | indra/newview/llpreviewnotecard.h | 15 | ||||
| -rw-r--r-- | indra/newview/llpreviewscript.cpp | 17 | ||||
| -rw-r--r-- | indra/newview/llpreviewscript.h | 18 | ||||
| -rw-r--r-- | indra/newview/skins/default/xui/en/floater_preview_notecard.xml | 12 | 
5 files changed, 203 insertions, 25 deletions
| diff --git a/indra/newview/llpreviewnotecard.cpp b/indra/newview/llpreviewnotecard.cpp index d4a8bbdf45..f012d99adf 100644 --- a/indra/newview/llpreviewnotecard.cpp +++ b/indra/newview/llpreviewnotecard.cpp @@ -32,6 +32,7 @@  #include "llagent.h"  #include "lldraghandle.h" +#include "llexternaleditor.h"  #include "llviewerwindow.h"  #include "llbutton.h"  #include "llfloaterreg.h" @@ -63,7 +64,8 @@  // Default constructor  LLPreviewNotecard::LLPreviewNotecard(const LLSD& key) //const LLUUID& item_id,  -	: LLPreview( key ) +	: LLPreview( key ), +	mLiveFile(NULL)  {  	const LLInventoryItem *item = getItem();  	if (item) @@ -74,13 +76,14 @@ LLPreviewNotecard::LLPreviewNotecard(const LLSD& key) //const LLUUID& item_id,  LLPreviewNotecard::~LLPreviewNotecard()  { +	delete mLiveFile;  }  BOOL LLPreviewNotecard::postBuild()  { -	LLViewerTextEditor *ed = getChild<LLViewerTextEditor>("Notecard Editor"); -	ed->setNotecardInfo(mItemUUID, mObjectID, getKey()); -	ed->makePristine(); +	mEditor = getChild<LLViewerTextEditor>("Notecard Editor"); +	mEditor->setNotecardInfo(mItemUUID, mObjectID, getKey()); +	mEditor->makePristine();  	childSetAction("Save", onClickSave, this);  	getChildView("lock")->setVisible( FALSE);	 @@ -88,6 +91,8 @@ BOOL LLPreviewNotecard::postBuild()  	childSetAction("Delete", onClickDelete, this);  	getChildView("Delete")->setEnabled(false); +	childSetAction("Edit", onClickEdit, this); +  	const LLInventoryItem* item = getItem();  	childSetCommitCallback("desc", LLPreview::onText, this); @@ -408,6 +413,16 @@ void LLPreviewNotecard::onClickDelete(void* user_data)  	}  } +// static +void LLPreviewNotecard::onClickEdit(void* user_data) +{ +	LLPreviewNotecard* preview = (LLPreviewNotecard*)user_data; +	if (preview) +	{ +		preview->openInExternalEditor(); +	} +} +  struct LLSaveNotecardInfo  {  	LLPreviewNotecard* mSelf; @@ -468,7 +483,7 @@ void LLPreviewNotecard::finishTaskUpload(LLUUID itemId, LLUUID newAssetId, LLUUI      }  } -bool LLPreviewNotecard::saveIfNeeded(LLInventoryItem* copyitem) +bool LLPreviewNotecard::saveIfNeeded(LLInventoryItem* copyitem, bool sync)  {  	LLViewerTextEditor* editor = getChild<LLViewerTextEditor>("Notecard Editor"); @@ -487,7 +502,10 @@ bool LLPreviewNotecard::saveIfNeeded(LLInventoryItem* copyitem)  		}  		editor->makePristine(); - +		if (sync) +		{ +			syncExternal(); +		}  		const LLInventoryItem* item = getItem();  		// save it out to database          if (item) @@ -566,6 +584,18 @@ bool LLPreviewNotecard::saveIfNeeded(LLInventoryItem* copyitem)  	return true;  } +void LLPreviewNotecard::syncExternal() +{ +	// Sync with external editor. +	std::string tmp_file = getTmpFileName(); +	llstat s; +	if (LLFile::stat(tmp_file, &s) == 0) // file exists +	{ +		if (mLiveFile) mLiveFile->ignoreNextUpdate(); +		writeToFile(tmp_file); +	} +} +  void LLPreviewNotecard::deleteNotecard()  {  	LLNotificationsUtil::add("DeleteNotecard", LLSD(), LLSD(), boost::bind(&LLPreviewNotecard::handleConfirmDeleteDialog,this, _1, _2)); @@ -714,4 +744,128 @@ bool LLPreviewNotecard::handleConfirmDeleteDialog(const LLSD& notification, cons  	return false;  } +void LLPreviewNotecard::openInExternalEditor() +{ +    delete mLiveFile; // deletes file + +    // Save the notecard to a temporary file. +    std::string filename = getTmpFileName(); +    writeToFile(filename); + +    // Start watching file changes. +    mLiveFile = new LLLiveLSLFile(filename, boost::bind(&LLPreviewNotecard::onExternalChange, this, _1)); +    mLiveFile->addToEventTimer(); + +    // Open it in external editor. +    { +        LLExternalEditor ed; +        LLExternalEditor::EErrorCode status; +        std::string msg; + +        status = ed.setCommand("LL_SCRIPT_EDITOR"); +        if (status != LLExternalEditor::EC_SUCCESS) +        { +            if (status == LLExternalEditor::EC_NOT_SPECIFIED) // Use custom message for this error. +            { +                msg = getString("external_editor_not_set"); +            } +            else +            { +                msg = LLExternalEditor::getErrorMessage(status); +            } + +            LLNotificationsUtil::add("GenericAlert", LLSD().with("MESSAGE", msg)); +            return; +        } + +        status = ed.run(filename); +        if (status != LLExternalEditor::EC_SUCCESS) +        { +            msg = LLExternalEditor::getErrorMessage(status); +            LLNotificationsUtil::add("GenericAlert", LLSD().with("MESSAGE", msg)); +        } +    } +} + +bool LLPreviewNotecard::onExternalChange(const std::string& filename) +{ +    if (!loadNotecardText(filename)) +    { +        return false; +    } + +    // Disable sync to avoid recursive load->save->load calls. +    saveIfNeeded(NULL, false); +    return true; +} + +bool LLPreviewNotecard::loadNotecardText(const std::string& filename) +{ +    if (filename.empty()) +    { +        LL_WARNS() << "Empty file name" << LL_ENDL; +        return false; +    } + +    LLFILE* file = LLFile::fopen(filename, "rb");		/*Flawfinder: ignore*/ +    if (!file) +    { +        LL_WARNS() << "Error opening " << filename << LL_ENDL; +        return false; +    } + +    // read in the whole file +    fseek(file, 0L, SEEK_END); +    size_t file_length = (size_t)ftell(file); +    fseek(file, 0L, SEEK_SET); +    char* buffer = new char[file_length + 1]; +    size_t nread = fread(buffer, 1, file_length, file); +    if (nread < file_length) +    { +        LL_WARNS() << "Short read" << LL_ENDL; +    } +    buffer[nread] = '\0'; +    fclose(file); + +    mEditor->setText(LLStringExplicit(buffer)); +    delete[] buffer; + +    return true; +} + +bool LLPreviewNotecard::writeToFile(const std::string& filename) +{ +    LLFILE* fp = LLFile::fopen(filename, "wb"); +    if (!fp) +    { +        LL_WARNS() << "Unable to write to " << filename << LL_ENDL; +        return false; +    } + +    std::string utf8text = mEditor->getText(); + +    if (utf8text.size() == 0) +    { +        utf8text = " "; +    } + +    fputs(utf8text.c_str(), fp); +    fclose(fp); +    return true; +} + + +std::string LLPreviewNotecard::getTmpFileName() +{ +    std::string notecard_id = mObjectID.asString() + "_" + mItemUUID.asString(); + +    // Use MD5 sum to make the file name shorter and not exceed maximum path length. +    char notecard_id_hash_str[33];			   /* Flawfinder: ignore */ +    LLMD5 notecard_id_hash((const U8 *)notecard_id.c_str()); +    notecard_id_hash.hex_digest(notecard_id_hash_str); + +    return std::string(LLFile::tmpdir()) + "sl_notecard_" + notecard_id_hash_str + ".txt"; +} + +  // EOF diff --git a/indra/newview/llpreviewnotecard.h b/indra/newview/llpreviewnotecard.h index 8908078c63..d9c14815c1 100644 --- a/indra/newview/llpreviewnotecard.h +++ b/indra/newview/llpreviewnotecard.h @@ -29,6 +29,7 @@  #include "llpreview.h"  #include "llassetstorage.h" +#include "llpreviewscript.h"  #include "lliconctrl.h"  //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -72,11 +73,13 @@ public:  	// asset system. :(  	void refreshFromInventory(const LLUUID& item_id = LLUUID::null); +	void syncExternal(); +  protected:  	void updateTitleButtons() override;  	void loadAsset() override; -	bool saveIfNeeded(LLInventoryItem* copyitem = NULL); +	bool saveIfNeeded(LLInventoryItem* copyitem = NULL, bool sync = true);  	void deleteNotecard(); @@ -89,6 +92,8 @@ protected:  	static void onClickDelete(void* data); +	static void onClickEdit(void* data); +  	static void onSaveComplete(const LLUUID& asset_uuid,  							   void* user_data,  							   S32 status, LLExtStat ext_status); @@ -99,6 +104,12 @@ protected:      static void finishInventoryUpload(LLUUID itemId, LLUUID newAssetId, LLUUID newItemId);      static void finishTaskUpload(LLUUID itemId, LLUUID newAssetId, LLUUID taskId); +    void openInExternalEditor(); +    bool onExternalChange(const std::string& filename); +    bool loadNotecardText(const std::string& filename); +    bool writeToFile(const std::string& filename); +    std::string getTmpFileName(); +  protected:  	LLViewerTextEditor* mEditor;  	LLButton* mSaveBtn; @@ -106,6 +117,8 @@ protected:  	LLUUID mAssetID;  	LLUUID mObjectID; + +	LLLiveLSLFile* mLiveFile;  }; diff --git a/indra/newview/llpreviewscript.cpp b/indra/newview/llpreviewscript.cpp index 9431914ba3..76a21077ba 100644 --- a/indra/newview/llpreviewscript.cpp +++ b/indra/newview/llpreviewscript.cpp @@ -41,7 +41,6 @@  #include "llinventorymodel.h"  #include "llkeyboard.h"  #include "lllineeditor.h" -#include "lllivefile.h"  #include "llhelp.h"  #include "llnotificationsutil.h"  #include "llresmgr.h" @@ -120,22 +119,6 @@ static bool have_script_upload_cap(LLUUID& object_id)  /// ---------------------------------------------------------------------------  /// LLLiveLSLFile  /// --------------------------------------------------------------------------- -class LLLiveLSLFile : public LLLiveFile -{ -public: -	typedef boost::function<bool (const std::string& filename)> change_callback_t; - -	LLLiveLSLFile(std::string file_path, change_callback_t change_cb); -	~LLLiveLSLFile(); - -	void ignoreNextUpdate() { mIgnoreNextUpdate = true; } - -protected: -	/*virtual*/ bool loadFile(); - -	change_callback_t	mOnChangeCallback; -	bool				mIgnoreNextUpdate; -};  LLLiveLSLFile::LLLiveLSLFile(std::string file_path, change_callback_t change_cb)  :	mOnChangeCallback(change_cb) diff --git a/indra/newview/llpreviewscript.h b/indra/newview/llpreviewscript.h index 69cf9d9158..74e4c00d43 100644 --- a/indra/newview/llpreviewscript.h +++ b/indra/newview/llpreviewscript.h @@ -34,6 +34,7 @@  #include "lliconctrl.h"  #include "llframetimer.h"  #include "llfloatergotoline.h" +#include "lllivefile.h"  #include "llsyntaxid.h"  class LLLiveLSLFile; @@ -53,6 +54,23 @@ class LLScriptEdContainer;  class LLFloaterGotoLine;  class LLFloaterExperienceProfile; +class LLLiveLSLFile : public LLLiveFile +{ +public: +    typedef boost::function<bool(const std::string& filename)> change_callback_t; + +    LLLiveLSLFile(std::string file_path, change_callback_t change_cb); +    ~LLLiveLSLFile(); + +    void ignoreNextUpdate() { mIgnoreNextUpdate = true; } + +protected: +    /*virtual*/ bool loadFile(); + +    change_callback_t	mOnChangeCallback; +    bool				mIgnoreNextUpdate; +}; +  // Inner, implementation class.  LLPreviewScript and LLLiveLSLEditor each own one of these.  class LLScriptEdCore : public LLPanel  { diff --git a/indra/newview/skins/default/xui/en/floater_preview_notecard.xml b/indra/newview/skins/default/xui/en/floater_preview_notecard.xml index 2e1c8ce670..dcbdfa8794 100644 --- a/indra/newview/skins/default/xui/en/floater_preview_notecard.xml +++ b/indra/newview/skins/default/xui/en/floater_preview_notecard.xml @@ -6,7 +6,7 @@   height="361"   layout="topleft"   min_height="243" - min_width="234" + min_width="330"   name="preview notecard"   help_topic="preview_notecard"   title="NOTECARD:" @@ -77,6 +77,16 @@       word_wrap="true">          Loading...      </text_editor> +      <button +     follows="left|bottom" +     height="22" +     label="Edit..." +     label_selected="Edit" +     layout="topleft" +     left="4" +     name="Edit" +     top="332" +     width="100" />      <button       follows="right|bottom"       height="22" | 
