aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/linden/indra/newview/llpreviewscript.cpp
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--linden/indra/newview/llpreviewscript.cpp318
1 files changed, 311 insertions, 7 deletions
diff --git a/linden/indra/newview/llpreviewscript.cpp b/linden/indra/newview/llpreviewscript.cpp
index d2d9ed5..ca4dcb7 100644
--- a/linden/indra/newview/llpreviewscript.cpp
+++ b/linden/indra/newview/llpreviewscript.cpp
@@ -170,15 +170,26 @@ LLScriptEdCore::LLScriptEdCore(
170 mSampleText(sample), 170 mSampleText(sample),
171 mHelpURL(help_url), 171 mHelpURL(help_url),
172 mEditor( NULL ), 172 mEditor( NULL ),
173 mFunctions(NULL),
174 mErrorList(NULL),
173 mLoadCallback( load_callback ), 175 mLoadCallback( load_callback ),
174 mSaveCallback( save_callback ), 176 mSaveCallback( save_callback ),
175 mSearchReplaceCallback( search_replace_callback ), 177 mSearchReplaceCallback( search_replace_callback ),
176 mUserdata( userdata ), 178 mUserdata( userdata ),
177 mForceClose( FALSE ), 179 mForceClose( FALSE ),
180 mLiveHelpHandle(),
181 mLiveHelpTimer(),
178 mLastHelpToken(NULL), 182 mLastHelpToken(NULL),
179 mLiveHelpHistorySize(0), 183 mLiveHelpHistorySize(0),
180 mEnableSave(FALSE), 184 mEnableSave(FALSE),
181 mHasScriptData(FALSE) 185 mEnableXEd(FALSE),
186 mXstbuf(),
187 mXfname(""),
188 mAutosaveFilename(""),
189 mHasScriptData(FALSE),
190 // We need to check for a new file every five seconds, or autosave every 60.
191 // There's probably a better solution to both of the above.
192 LLEventTimer((gSavedSettings.getString("LSLExternalEditor").length() < 3) ? 60 : 5)
182{ 193{
183 setFollowsAll(); 194 setFollowsAll();
184 setBorderVisible(FALSE); 195 setBorderVisible(FALSE);
@@ -209,11 +220,30 @@ LLScriptEdCore::LLScriptEdCore(
209 tooltips.push_back(ll_safe_string(gScriptLibrary.mFunctions[i]->mDesc)); 220 tooltips.push_back(ll_safe_string(gScriptLibrary.mFunctions[i]->mDesc));
210 } 221 }
211 } 222 }
223
224 //gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS,"keywords.ini")
225 std::string keyword_path = gDirUtilp->getUserSkinDir() + gDirUtilp->getDirDelimiter() + "keywords.ini";
226 if(!LLFile::isfile(keyword_path))
227 {
228 llinfos << "nothing at " << keyword_path << llendl;
229 keyword_path = gDirUtilp->getSkinDir() + gDirUtilp->getDirDelimiter() + "keywords.ini";
230 if(!LLFile::isfile(keyword_path))
231 {
232 llinfos << "nothing at " << keyword_path << " ; will use default" << llendl;
233 keyword_path = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "keywords.ini");
234 }
235 else
236 {
237 llinfos << "loaded skin-specific keywords from " << keyword_path << llendl;
238 }
239 }
240 else
241 {
242 llinfos << "loaded skin-specific keywords from " << keyword_path << llendl;
243 }
212 LLColor3 color(0.5f, 0.0f, 0.15f); 244 LLColor3 color(0.5f, 0.0f, 0.15f);
213 245 mEditor->loadKeywords(keyword_path, funcs, tooltips, color);
214 mEditor->loadKeywords(gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS,"keywords.ini"), funcs, tooltips, color);
215 246
216
217 LLKeywordToken *token; 247 LLKeywordToken *token;
218 LLKeywords::keyword_iterator_t token_it; 248 LLKeywords::keyword_iterator_t token_it;
219 for (token_it = mEditor->keywordsBegin(); token_it != mEditor->keywordsEnd(); ++token_it) 249 for (token_it = mEditor->keywordsBegin(); token_it != mEditor->keywordsEnd(); ++token_it)
@@ -233,7 +263,6 @@ LLScriptEdCore::LLScriptEdCore(
233 263
234 childSetCommitCallback("lsl errors", &LLScriptEdCore::onErrorList, this); 264 childSetCommitCallback("lsl errors", &LLScriptEdCore::onErrorList, this);
235 childSetAction("Save_btn", onBtnSave,this); 265 childSetAction("Save_btn", onBtnSave,this);
236
237 initMenu(); 266 initMenu();
238 267
239 // Do the work that addTabPanel() normally does. 268 // Do the work that addTabPanel() normally does.
@@ -250,6 +279,27 @@ LLScriptEdCore::~LLScriptEdCore()
250 deleteBridges(); 279 deleteBridges();
251} 280}
252 281
282BOOL LLScriptEdCore::tick()
283{
284 //autoSave();
285 if (gSavedSettings.getString("LSLExternalEditor").length() < 3)
286 {
287 if (hasChanged(this))
288 {
289 autoSave();
290 }
291 }
292 else
293 {
294 // This should really be passed as a parameter -- MC
295 if (!mXfname.empty())
296 {
297 xedUpdateScript();
298 }
299 }
300 return FALSE;
301}
302
253void LLScriptEdCore::initMenu() 303void LLScriptEdCore::initMenu()
254{ 304{
255 305
@@ -297,6 +347,14 @@ void LLScriptEdCore::initMenu()
297 menuItem->setMenuCallback(onBtnHelp, this); 347 menuItem->setMenuCallback(onBtnHelp, this);
298 menuItem->setEnabledCallback(NULL); 348 menuItem->setEnabledCallback(NULL);
299 349
350 menuItem = getChild<LLMenuItemCallGL>("Set External Editor...");
351 menuItem->setMenuCallback(onSetExternalEditor, this);
352 menuItem->setEnabledCallback(NULL);
353
354 menuItem = getChild<LLMenuItemCallGL>("Open in External Editor");
355 menuItem->setMenuCallback(onBtnXEd, this);
356 menuItem->setEnabledCallback(enableExternalEditor);
357
300 menuItem = getChild<LLMenuItemCallGL>("Import Script..."); 358 menuItem = getChild<LLMenuItemCallGL>("Import Script...");
301 menuItem->setMenuCallback(onBtnLoadFromDisc, this); 359 menuItem->setMenuCallback(onBtnLoadFromDisc, this);
302 menuItem->setEnabledCallback(NULL); 360 menuItem->setEnabledCallback(NULL);
@@ -318,7 +376,9 @@ void LLScriptEdCore::setScriptText(const std::string& text, BOOL is_valid)
318{ 376{
319 if (mEditor) 377 if (mEditor)
320 { 378 {
321 mEditor->setText(text); 379 std::string new_text(text);
380 LLStringUtil::replaceTabsWithSpaces(new_text, 4); // fix tabs in text
381 mEditor->setText(new_text);
322 mHasScriptData = is_valid; 382 mHasScriptData = is_valid;
323 } 383 }
324} 384}
@@ -416,6 +476,177 @@ void LLScriptEdCore::updateDynamicHelp(BOOL immediate)
416 setHelpPage(LLStringUtil::null); 476 setHelpPage(LLStringUtil::null);
417 } 477 }
418} 478}
479//dim
480void LLScriptEdCore::xedLaunch()
481{
482 //llinfos << "LLScriptEdCore::autoSave()" << llendl;
483
484 std::string editor = gSavedSettings.getString("LSLExternalEditor");
485 if (!gDirUtilp->fileExists(editor))
486 {
487 llwarns << "External editor " + editor + " not found" << llendl;
488
489 LLSD row;
490 row["columns"][0]["value"] = "Couldn't open external editor '" + editor + "'. File not found.";
491 row["columns"][0]["font"] = "SANSSERIF_SMALL";
492 mErrorList->addElement(row);
493 return;
494 }
495
496 //std::string filepath = gDirUtilp->getExpandedFilename(gDirUtilp->getTempDir(),asset_id.asString());
497 if( mXfname.empty() )
498 {
499 std::string asfilename = gDirUtilp->getTempFilename();
500 asfilename.replace( asfilename.length()-4, 12, "_Xed.lsl" );
501 mXfname = asfilename;
502 //mAutosaveFilename = llformat("%s.lsl", asfilename.c_str());
503 }
504
505 FILE* fp = LLFile::fopen(mXfname.c_str(), "wb");
506 if(!fp)
507 {
508 llwarns << "Unable to write to " << mXfname << llendl;
509
510 LLSD row;
511 row["columns"][0]["value"] = "Error writing to temp file. Is your hard drive full?";
512 row["columns"][0]["font"] = "SANSSERIF_SMALL";
513 mErrorList->addElement(row);
514 return;
515 }
516 mEditor->setEnabled(FALSE);
517 std::string utf8text = mEditor->getText();
518 fputs(utf8text.c_str(), fp);
519 fclose(fp);
520 fp = NULL;
521 llinfos << "XEditor: " << mXfname << llendl;
522 //record the stat
523 LLFile::stat(mXfname.c_str(), &mXstbuf);
524 //launch
525#if LL_WINDOWS
526 //just to get rid of the pesky black window
527 std::string exe = gSavedSettings.getString("LSLExternalEditor");
528 S32 spaces=0;
529 for(S32 i=0; i!=exe.size(); ++i)
530 {
531 spaces+=( exe.at(i)==' ');
532 }
533 if(spaces > 0)
534 {
535 exe = "\""+exe+"\"";
536 }
537 std::string theCMD("%COMSPEC% /c START \"External Editor\" " + exe + " " + mXfname + " & exit");
538 llinfos << "FINAL COMMAND IS :"<<
539 theCMD.c_str() << llendl;
540
541 std::system(theCMD.c_str());
542#elif LL_DARWIN
543 // Use Launch Services for this - launching another instance is fail (and incorrect on OS X)
544 CFStringRef strPath = CFStringCreateWithCString(kCFAllocatorDefault, mXfname.c_str(), kCFStringEncodingUTF8);
545 CFURLRef tempPath = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, strPath, kCFURLPOSIXPathStyle, false);
546 CFURLRef tempPathArray[1] = { tempPath };
547 CFArrayRef arguments = CFArrayCreate(kCFAllocatorDefault, (const void **)tempPathArray, 1, NULL);
548 LSApplicationParameters appParams;
549 memset(&appParams, 0, sizeof(appParams));
550 FSRef ref;
551 FSPathMakeRef((UInt8*)gSavedSettings.getString("LSLExternalEditor").c_str(), &ref, NULL);
552 appParams.application = &ref;
553 appParams.flags = kLSLaunchAsync | kLSLaunchStartClassic;
554 LSOpenURLsWithRole(arguments, kLSRolesAll, NULL, &appParams, NULL, 0);
555 CFRelease(arguments);
556 CFRelease(tempPath);
557 CFRelease(strPath);
558#else
559 //std::system(std::string(gSavedSettings.getString("LSLExternalEditor") + " " + mXfname).c_str());
560
561 // Any approach involving std::system will fail because SL eats signals.
562 // This was stolen from floaterskinfinder.cpp.
563 std::string exe = gSavedSettings.getString("LSLExternalEditor");
564 const char *zargv[] = {exe.c_str(), mXfname.c_str(), NULL};
565 fflush(NULL);
566 pid_t id = vfork();
567 if(id == 0)
568 {
569 execv(exe.c_str(), (char **)zargv);
570 _exit(0); // This shouldn't ever be reached.
571 }
572#endif
573}
574
575void LLScriptEdCore::xedUpdateScript()
576{
577 llstat stbuf;
578 if (LLFile::stat(this->mXfname.c_str() , &stbuf) == 0) // info found
579 {
580 if (this->mXstbuf.st_mtime != stbuf.st_mtime)
581 {
582 this->mErrorList->addCommentText(std::string("Change Detected... Updating"));
583
584 this->mXstbuf = stbuf;
585 LLFILE* file = LLFile::fopen(this->mXfname, "rb"); /*Flawfinder: ignore*/
586 if(file)
587 {
588 // read in the whole file
589 fseek(file, 0L, SEEK_END);
590 S64 file_length = ftell(file);
591 fseek(file, 0L, SEEK_SET);
592 char* buffer = new char[file_length+1];
593 size_t nread = fread(buffer, 1, file_length, file);
594 if (nread < (size_t) file_length)
595 {
596 llwarns << "Short read" << llendl;
597 }
598 buffer[nread] = '\0';
599 fclose(file);
600 std::string ttext = LLStringExplicit(buffer);
601 LLStringUtil::replaceTabsWithSpaces(ttext, 4);
602 mEditor->setText(ttext);
603 LLScriptEdCore::doSave( this, FALSE );
604 //mEditor->makePristine();
605 delete[] buffer;
606 buffer = NULL;
607 }
608 else
609 {
610 llwarns << "Error opening " << this->mXfname << llendl;
611 }
612 }
613 }
614}
615//end dim
616void LLScriptEdCore::autoSave()
617{
618 //llinfos << "LLScriptEdCore::autoSave()" << llendl;
619 if(mEditor->isPristine())
620 {
621 return;
622 }
623 //std::string filepath = gDirUtilp->getExpandedFilename(gDirUtilp->getTempDir(),asset_id.asString());
624 if( mAutosaveFilename.empty() )
625 {
626 std::string asfilename = gDirUtilp->getTempFilename();
627 asfilename.replace( asfilename.length()-4, 12, "_autosave.lsl" );
628 mAutosaveFilename = asfilename;
629 //mAutosaveFilename = llformat("%s.lsl", asfilename.c_str());
630 }
631
632 FILE* fp = LLFile::fopen(mAutosaveFilename.c_str(), "wb");
633 if(!fp)
634 {
635 llwarns << "Unable to write to " << mAutosaveFilename << llendl;
636
637 LLSD row;
638 row["columns"][0]["value"] = "Error writing to temp file. Is your hard drive full?";
639 row["columns"][0]["font"] = "SANSSERIF_SMALL";
640 mErrorList->addElement(row);
641 return;
642 }
643
644 std::string utf8text = mEditor->getText();
645 fputs(utf8text.c_str(), fp);
646 fclose(fp);
647 fp = NULL;
648 llinfos << "autosave: " << mAutosaveFilename << llendl;
649}
419 650
420void LLScriptEdCore::setHelpPage(const std::string& help_string) 651void LLScriptEdCore::setHelpPage(const std::string& help_string)
421{ 652{
@@ -507,6 +738,16 @@ bool LLScriptEdCore::handleSaveChangesDialog(const LLSD& notification, const LLS
507 break; 738 break;
508 739
509 case 1: // "No" 740 case 1: // "No"
741 if( !mAutosaveFilename.empty())
742 {
743 llinfos << "remove autosave: " << mAutosaveFilename << llendl;
744 LLFile::remove(mAutosaveFilename.c_str());
745 }
746 if( !mXfname.empty())
747 {
748 llinfos << "remove autosave: " << mXfname << llendl;
749 LLFile::remove(mXfname.c_str());
750 }
510 mForceClose = TRUE; 751 mForceClose = TRUE;
511 // This will close immediately because mForceClose is true, so we won't 752 // This will close immediately because mForceClose is true, so we won't
512 // infinite loop with these dialogs. JC 753 // infinite loop with these dialogs. JC
@@ -724,6 +965,34 @@ void LLScriptEdCore::onBtnSave(void* data)
724} 965}
725 966
726// static 967// static
968void LLScriptEdCore::onSetExternalEditor(void* data)
969{
970 std::string cur_name(gSavedSettings.getString("LSLExternalEditor"));
971
972 LLFilePicker& picker = LLFilePicker::instance();
973 if (! picker.getOpenFile(LLFilePicker::FFLOAD_APP) )
974 {
975 return; //Canceled!
976 }
977 std::string file_name = picker.getFirstFile();
978 if (!file_name.empty() && file_name != cur_name)
979 {
980 gSavedSettings.setString("LSLExternalEditor", file_name);
981 }
982 else
983 {
984 gSavedSettings.setString("LSLExternalEditor", "");
985 }
986}
987
988//static
989void LLScriptEdCore::onBtnXEd(void* data)
990{
991 LLScriptEdCore* self = (LLScriptEdCore*)data;
992 self->xedLaunch();
993}
994
995// static
727void LLScriptEdCore::onBtnUndoChanges( void* userdata ) 996void LLScriptEdCore::onBtnUndoChanges( void* userdata )
728{ 997{
729 LLScriptEdCore* self = (LLScriptEdCore*) userdata; 998 LLScriptEdCore* self = (LLScriptEdCore*) userdata;
@@ -904,6 +1173,12 @@ BOOL LLScriptEdCore::enableDeselectMenu(void* userdata)
904} 1173}
905 1174
906// static 1175// static
1176BOOL LLScriptEdCore::enableExternalEditor(void* userdata)
1177{
1178 return (gSavedSettings.getString("LSLExternalEditor").length() > 3);
1179}
1180
1181// static
907void LLScriptEdCore::onErrorList(LLUICtrl*, void* user_data) 1182void LLScriptEdCore::onErrorList(LLUICtrl*, void* user_data)
908{ 1183{
909 LLScriptEdCore* self = (LLScriptEdCore*)user_data; 1184 LLScriptEdCore* self = (LLScriptEdCore*)user_data;
@@ -989,6 +1264,11 @@ BOOL LLScriptEdCore::handleKeyHere(KEY key, MASK mask)
989 if(mSaveCallback) 1264 if(mSaveCallback)
990 { 1265 {
991 // don't close after saving 1266 // don't close after saving
1267 if (!hasChanged(this))
1268 {
1269 llinfos << "Save Not Needed" << llendl;
1270 return TRUE;
1271 }
992 mSaveCallback(mUserdata, FALSE); 1272 mSaveCallback(mUserdata, FALSE);
993 } 1273 }
994 1274
@@ -1081,6 +1361,15 @@ LLPreviewLSL::LLPreviewLSL(const std::string& name, const LLRect& rect,
1081 } 1361 }
1082} 1362}
1083 1363
1364LLPreviewLSL::~LLPreviewLSL()
1365{
1366 if (mScriptEd && !(mScriptEd->mXfname.empty()))
1367 {
1368 llinfos << "remove autosave: " << mScriptEd->mXfname << llendl;
1369 LLFile::remove(mScriptEd->mXfname.c_str());
1370 }
1371}
1372
1084// virtual 1373// virtual
1085void LLPreviewLSL::callbackLSLCompileSucceeded() 1374void LLPreviewLSL::callbackLSLCompileSucceeded()
1086{ 1375{
@@ -1181,6 +1470,11 @@ void LLPreviewLSL::closeIfNeeded()
1181 mPendingUploads--; 1470 mPendingUploads--;
1182 if (mPendingUploads <= 0 && mCloseAfterSave) 1471 if (mPendingUploads <= 0 && mCloseAfterSave)
1183 { 1472 {
1473 if (mScriptEd && !mScriptEd->mAutosaveFilename.empty())
1474 {
1475 llinfos << "remove autosave: " << mScriptEd->mAutosaveFilename << llendl;
1476 LLFile::remove(mScriptEd->mAutosaveFilename.c_str());
1477 }
1184 close(); 1478 close();
1185 } 1479 }
1186} 1480}
@@ -1634,7 +1928,12 @@ LLLiveLSLEditor::LLLiveLSLEditor(const std::string& name,
1634} 1928}
1635 1929
1636LLLiveLSLEditor::~LLLiveLSLEditor() 1930LLLiveLSLEditor::~LLLiveLSLEditor()
1637{ 1931{
1932 if (mScriptEd && (!(mScriptEd->mXfname.empty())))
1933 {
1934 llinfos << "remove autosave: " << mScriptEd->mXfname << llendl;
1935 LLFile::remove(mScriptEd->mXfname.c_str());
1936 }
1638 LLLiveLSLEditor::sInstances.removeData(mItemID ^ mObjectID); 1937 LLLiveLSLEditor::sInstances.removeData(mItemID ^ mObjectID);
1639} 1938}
1640 1939
@@ -2349,6 +2648,11 @@ void LLLiveLSLEditor::closeIfNeeded()
2349 mPendingUploads--; 2648 mPendingUploads--;
2350 if (mPendingUploads <= 0 && mCloseAfterSave) 2649 if (mPendingUploads <= 0 && mCloseAfterSave)
2351 { 2650 {
2651 if (mScriptEd && (!mScriptEd->mAutosaveFilename.empty()))
2652 {
2653 llinfos << "remove autosave: " << mScriptEd->mAutosaveFilename << llendl;
2654 LLFile::remove(mScriptEd->mAutosaveFilename.c_str());
2655 }
2352 close(); 2656 close();
2353 } 2657 }
2354} 2658}