1 /*
2 * DuneApp.cpp
3 *
4 * Copyright (C) 1999 Stephen F. White
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program (see the file "COPYING" for details); if
18 * not, write to the Free Software Foundation, Inc., 675 Mass Ave,
19 * Cambridge, MA 02139, USA.
20 */
21
22 #include <errno.h>
23 #ifdef _WIN32
24 # include <direct.h>
25 #endif
26
27 #include <sys/types.h>
28 #include <sys/stat.h>
29 #ifndef _WIN32
30 # include <unistd.h>
31 # include <signal.h>
32 #endif
33
34 #include <ctype.h>
35 #include <time.h>
36
37 #include "stdafx.h"
38 #include "swt.h"
39
40 #include "parser.h"
41 #include "DuneApp.h"
42 #include "Scene.h"
43 #include "Path.h"
44 #include "MainWindow.h"
45 #include "URL.h"
46 #include "EulerAngles.h"
47 #include "resource.h"
48 #include "TexteditSettingsDialog.h"
49 #include "xerrorhandler.h"
50 #include "WriteFlags.h"
51
52 #ifdef HAVE_OLPC
53 #define DEFAULT_WIDTH 1200
54 #define DEFAULT_HEIGHT 900
55 #else
56 #define DEFAULT_WIDTH 1090
57 #define DEFAULT_HEIGHT 700
58 #endif
59
60 DuneApp *TheApp = NULL;
61 extern void setLanguage(char *lang);
62
returntracker(void)63 void returntracker(void)
64 {
65 TheApp->returnTracker();
66 }
67
68 #define MAX_RECENT_FILES 4
69
DuneApp()70 DuneApp::DuneApp() : PreferencesApp(), EcmaScriptApp(), StereoViewApp(),
71 InputDeviceApp()
72 {
73 TheApp = this;
74 m_downloadDirectory = "";
75 swSetDefaultIcon(IDI_DUNE_ICON);
76 m_mainWnd = NULL;
77
78 initPreferences();
79
80 int n = GetIntPreference("RecentFiles", 0);
81 for (int i = 0; i < n; i++) {
82 char buf[1024];
83 const char *filename;
84 mysnprintf(buf, 1024, "RecentFile%d", i);
85 filename = TheApp->GetPreference(buf, "");
86 m_recentFiles.append(filename);
87 }
88 m_clipboardNode = NULL;
89 swSetCleanup(returntracker);
90 init_handlers();
91 m_currentWindow = NULL;
92 m_keyProtoFile = "ProtoFile";
93 m_keyProtoCategory = "ProtoCategory";
94 m_is4Kids = false;
95 m_is4Catt = false;
96 m_x3dv = false;
97 m_numberLoadedInlines = 0;
98 m_coverMode = false;
99 m_kambiMode = false;
100 m_x3domMode = false;
101 m_importURL = "";
102 m_oldImportURL = "";
103 m_importFile = "";
104 m_fileDialogDir = NULL;
105 m_createAtZero[0] = false;
106 m_createAtZero[1] = false;
107 m_createAtZero[2] = false;
108 m_blackAndWhiteIcons = false;
109 m_glErrorCount = 0;
110 m_vrml1Error = false;
111 m_timeOut = -1;
112 m_timeOutSet = true;
113 m_lastInteraction = -1;
114 m_tessellation = DEFAULT_TESSELLATION;
115 if (m_tessellation <= 8)
116 m_tessellation = 8;
117 setLanguage(TheApp->GetStartLanguage());
118 char *variant = TheApp->GetStartVariant();
119 if (variant) {
120 if (strcmp(variant, "4kids") == 0)
121 TheApp->set4Kids();
122 if (strcmp(variant, "4catt") == 0)
123 TheApp->set4Catt();
124 if (strcmp(variant, "cover") == 0)
125 TheApp->setCoverMode();
126 if (strcmp(variant, "kambi") == 0)
127 TheApp->setKambiMode();
128 if (strcmp(variant, "x3dom") == 0)
129 TheApp->setX3domMode();
130 }
131 m_selectionLinenumberFlag = false;
132 m_renderFaster = true;
133 m_trackAnimation = false;
134 m_checkSimpleCyclicSceneGraph = false;
135 setScriptHeaderC("c:");
136 setScriptHeaderCpp("c++:");
137 setScriptHeaderJava("java:");
138 m_hideStandardToolbar = false;
139 m_importingDataFile = false;
140 m_importingProtoLibrary = false;
141 m_verbose = false;
142 m_disableGlList = false;
143 m_numExportFiles = 1;
144 m_exitPid = 0;
145 m_fullScreenAtBegin = 0;
146 m_CExporting = false;
147 m_skipChecks = false;
148 enableDraw();
149 enableMatrixParallel();
150 }
151
initPreferences(void)152 void DuneApp::initPreferences(void)
153 {
154 m_browser = swBrowserInit(getPrefs());
155 m_upload = swUploadInit(getPrefs());
156 m_helpBrowser = swHelpBrowserInit(getPrefs());
157 m_textedit = swTextEditInit(getPrefs());
158 StereoViewLoadPreferences();
159 EcmaScriptLoadPreferences();
160 OutputLoadPreferences();
161 RouteViewLoadPreferences();
162 StartWithLoadPreferences();
163 ModellingLoadPreferences();
164 RenderLoadPreferences();
165 // load InputDeviceLoadPreferences() later, may need GUI
166 m_loadInputDevicePreferences = true;
167 }
168
169 void
setDefaults(void)170 DuneApp::setDefaults(void)
171 {
172 swPreferencesDefault();
173 initPreferences();
174 PreferencesDefaults();
175 OutputSetDefaults();
176 RouteViewSetDefaults();
177 StartWithSetDefaults();
178 StereoViewSetDefaults();
179 }
180
181
182
183 void
SaveRecentFileList()184 DuneApp::SaveRecentFileList()
185 {
186 int i, n = m_recentFiles.size();
187
188 SetIntPreference("RecentFiles", n);
189 for (i = 0; i < n; i++) {
190 char buf[1024];
191 mysnprintf(buf, 1024, "RecentFile%d", i);
192 SetPreference(buf, m_recentFiles[i]);
193 }
194 }
195
196 // there may be only one message at a time
197
198 void
PrintMessageWindows(const char * text)199 DuneApp::PrintMessageWindows(const char *text)
200 {
201 bool written = false;
202 List<MainWindow *>::Iterator *i;
203 for (i = m_windows.first(); i; i = i->next()) {
204 written = true;
205 i->item()->setStatusText(text);
206 }
207 if (written == false)
208 swDebugf("%s\n", text);
209 }
210
211
212 void
PrintMessageWindowsId(int id)213 DuneApp::PrintMessageWindowsId(int id)
214 {
215 static char text[256];
216 swLoadString(id, text, 255);
217 PrintMessageWindows(text);
218 }
219
220 void
PrintMessageWindowsInt(int id,int integer)221 DuneApp::PrintMessageWindowsInt(int id, int integer)
222 {
223 char idText[256];
224 static char text[512];
225 swLoadString(id, idText, 255);
226 mysnprintf(text, 511, idText, integer);
227 PrintMessageWindows(text);
228
229 }
230
231 void
PrintMessageWindowsFloat(int id,float f)232 DuneApp::PrintMessageWindowsFloat(int id, float f)
233 {
234 char idText[256];
235 static char text[512];
236 swLoadString(id, idText, 255);
237 mysnprintf(text, 511, idText, f);
238 PrintMessageWindows(text);
239 }
240
241 void
PrintMessageWindowsString(int id,const char * string)242 DuneApp::PrintMessageWindowsString(int id, const char *string)
243 {
244 char idText[256];
245 static char text[512];
246 swLoadString(id, idText, 255);
247 mysnprintf(text, 511, idText, string);
248 PrintMessageWindows(text);
249 }
250
251
252 void
PrintMessageWindowsVertex(int id,const char * fieldName,int handle,Vec3f vec)253 DuneApp::PrintMessageWindowsVertex(int id, const char *fieldName, int handle,
254 Vec3f vec)
255 {
256 if (is4Kids())
257 return;
258 static char text[256];
259 static char idText[256];
260 swLoadString(id, idText, 255);
261 mysnprintf(text, 255, idText, fieldName, handle, vec.x, vec.y, vec.z);
262 PrintMessageWindows(text);
263 }
264
265 // there may be only one MessageBox at a time
266
267 char *
loadPrompt(int prompt)268 DuneApp::loadPrompt(int prompt)
269 {
270 static char string[256];
271 string[0] = 0;
272 if (prompt == SW_MB_ERROR)
273 swLoadString(IDS_DUNE_ERROR, string, 255);
274 else if (prompt == SW_MB_WARNING)
275 swLoadString(IDS_DUNE_WARNING, string, 255);
276 else
277 swLoadString(IDS_DUNE, string, 255);
278 return string;
279 }
280
281 void
MessageBox(const char * text,int prompt)282 DuneApp::MessageBox(const char *text, int prompt)
283 {
284 if (m_windows.size() == 0)
285 swDebugf("%s\n", text);
286 else
287 swMessageBox(m_mainWnd, text, loadPrompt(prompt), SW_MB_OK,
288 prompt == -1 ? SW_MB_ERROR : prompt);
289 }
290
291 void
MessageBoxId(int id,int prompt)292 DuneApp::MessageBoxId(int id, int prompt)
293 {
294 char string[256];
295 swLoadString(id, string, 255);
296 MessageBox(string, prompt);
297 }
298
299 void
MessageBox(int id,const char * str,int prompt)300 DuneApp::MessageBox(int id, const char *str, int prompt)
301 {
302 static char text[512];
303
304 char idText[256];
305 swLoadString(id, idText, 255);
306 mysnprintf(text, 511, idText, str);
307 MessageBox(text, prompt);
308 }
309
310 void
MessageBox(int id,const char * str1,const char * str2,int prompt)311 DuneApp::MessageBox(int id, const char *str1, const char *str2, int prompt)
312 {
313 static char text[1024];
314
315 char idText[256];
316 swLoadString(id, idText, 255);
317 mysnprintf(text, 1023, idText, str1, str2);
318 MessageBox(text, prompt);
319 }
320
321 void
MessageBox(int id,int integer,int prompt)322 DuneApp::MessageBox(int id, int integer, int prompt)
323 {
324 static char text[256];
325
326 char idText[256];
327 swLoadString(id, idText, 255);
328 mysnprintf(text, 255, idText, integer);
329 MessageBox(text, prompt);
330 }
331
332 void
MessageBox(int id,float f,int prompt)333 DuneApp::MessageBox(int id, float f, int prompt)
334 {
335 static char text[256];
336
337 char idText[256];
338 swLoadString(id, idText, 255);
339 mysnprintf(text, 255, idText, f);
340 MessageBox(text, prompt);
341 }
342
343 void
MessageBoxPerror(const char * object)344 DuneApp::MessageBoxPerror(const char *object)
345 {
346 char error[1024];
347 mysnprintf(error, 1023,"%s: %s", object, strerror(swGetLastError()));
348 MessageBox(error);
349 }
350
351 void
MessageBoxPerror(int id,const char * object)352 DuneApp::MessageBoxPerror(int id, const char *object)
353 {
354 MessageBox(id, object, strerror(swGetLastError()));
355 }
356
357
358 void
newMainWnd(SWND & mainWnd)359 DuneApp::newMainWnd(SWND &mainWnd)
360 {
361 int width = GetIntPreference("WindowWidth", DEFAULT_WIDTH);
362 int height = GetIntPreference("WindowHeight", DEFAULT_HEIGHT);
363 // sanity check
364 if ((width <= 0) || (height <= 0)) {
365 width = DEFAULT_WIDTH;
366 height = DEFAULT_HEIGHT;
367 }
368 mainWnd = swCreateMainWindow("Dune", 0, 0, width, height);
369 if (m_loadInputDevicePreferences) {
370 InputDeviceLoadPreferences();
371 m_loadInputDevicePreferences = false;
372 }
373 }
374
375 void
forgetClipBoardNode(void)376 DuneApp::forgetClipBoardNode(void)
377 {
378 if (m_clipboardNode)
379 m_clipboardNode->unref();
380 m_clipboardNode = NULL;
381 }
382
383 void
OnFileNew(int id)384 DuneApp::OnFileNew(int id)
385 {
386 #ifndef HAVE_OPEN_IN_NEW_WINDOW
387 if (!TheApp->checkSaveOldWindow())
388 return;
389 #endif
390
391 forgetNameTranslation();
392 forgetClipBoardNode();
393
394 Scene *scene = new Scene();
395 if (id == ID_DUNE_FILE_NEW_X3DV)
396 scene->setX3dv();
397 else if (id == ID_DUNE_FILE_NEW_X3D_XML)
398 scene->setX3dXml();
399 newMainWnd(m_mainWnd);
400 MainWindow *window = new MainWindow(scene, m_mainWnd);
401 m_windows.append(window);
402
403 #ifndef HAVE_OPEN_IN_NEW_WINDOW
404 TheApp->deleteOldWindow();
405 #endif
406 }
407
408 void
OnFileNewWindow()409 DuneApp::OnFileNewWindow()
410 {
411 Scene *scene = new Scene();
412 if (m_x3dv)
413 scene->setX3dv();
414 newMainWnd(m_mainWnd);
415 MainWindow *window = new MainWindow(scene, m_mainWnd);
416 m_windows.append(window);
417 }
418
419 const char*
getExtension(int writeFlags)420 DuneApp::getExtension(int writeFlags)
421 {
422 const char *ret = ".wrl";
423 switch (writeFlags) {
424 case X3D_XML:
425 ret = ".xml";
426 break;
427 case X3DV:
428 ret = ".x3dv";
429 break;
430 }
431 if (writeFlags & X3DOM)
432 ret = ".html";
433 if (writeFlags & XITE)
434 ret = ".html";
435 return ret;
436 }
437
438 /*
439 * temporary files are written into the current directory
440 * temporary files are written into a list and deleted at program end
441 */
442
443 char *
SaveTempFile(Scene * scene,const char * name,int writeFlags,char * wrlpath)444 DuneApp::SaveTempFile(Scene *scene, const char *name, int writeFlags,
445 char *wrlpath)
446 {
447 static char path[1024];
448
449 mystrncpy_secure(path,scene->getPath(),1024);
450 int i = 0;
451 // produce a absolute path (remote netscape commands need one)
452 #ifdef _WIN32
453 const char *dirsign="\\";
454 if (path[1] != ':')
455 if (getcwd(path, 1023)!=NULL) {
456 #else
457 const char *dirsign="/";
458 if (path[0] != '/')
459 if (getcwd(path, 1023)!=NULL) {
460 #endif
461 mystrncpy_secure(path+strlen(path),dirsign,1024-strlen(path));
462 mystrncpy_secure(path+strlen(path),scene->getPath(),
463 1024-strlen(path));
464 }
465 // strip filename
466 for (i = strlen(path);( i >= 0) && (path[i] != dirsign[0]); i--);
467 i++;
468 bool writeError = false;
469 if (writeFlags & X3DOM)
470 writeFlags |= PURE_X3D;
471 if (writeFlags & XITE) {
472 writeFlags |= PURE_X3DV | X3DV;
473 swGetTempFile(path+i, name, getExtension(X3DV), 1024-i);
474 int f = open(path, O_WRONLY | O_CREAT,00666);
475 if (f == -1) {
476 if (scene->write(f, path, (writeFlags | SKIP_SAVED_TEST |
477 (TEMP_SAVE & (~XITE)))))
478 writeError = true;
479 else if (swTruncateClose(f))
480 writeError = true;
481 AddToFilesToDelete(path);
482 }
483 }
484 swGetTempFile(path+i, name, getExtension(writeFlags), 1024-i);
485 int f = open(path, O_WRONLY | O_CREAT,00666);
486
487 if (f == -1) {
488 swGetTempPath(path, name, getExtension(writeFlags), 1024);
489 f = open(path, O_WRONLY | O_CREAT,00666);
490 if (f == -1) {
491 char errorstring1[256];
492 swLoadString(IDS_SAVE_PREVIEW_ERROR1, errorstring1, 255);
493 char errorstring2[256];
494 swLoadString(IDS_SAVE_PREVIEW_ERROR2, errorstring2, 255);
495 char msg[1024];
496 mysnprintf(msg, 1023, errorstring1, path, strerror(errno),
497 errorstring2);
498 TheApp->MessageBox(msg);
499 return (char *)"";
500 }
501 }
502 URL fileURL;
503 fileURL.FromPath(path);
504 bool oldKeepUrls = TheApp->GetKeepURLs();
505 TheApp->SetKeepURLs(true);
506 if (scene->write(f, path, writeFlags | TEMP_SAVE | SKIP_SAVED_TEST,
507 wrlpath))
508 writeError = true;
509 else if (swTruncateClose(f))
510 writeError = true;
511 TheApp->SetKeepURLs(oldKeepUrls);
512 if (writeError)
513 TheApp->MessageBoxPerror(path);
514 AddToFilesToDelete(path);
515 if (writeError)
516 return (char *)"";
517 return path;
518 }
519
520 void DuneApp::OnFilePreview(Scene* scene)
521 {
522 // stop animation
523 List<MainWindow *>::Iterator *wIter;
524 for (wIter = m_windows.first(); wIter != NULL; wIter = wIter->next()) {
525 #ifndef _WIN32
526 if (swBrowserGetUseFork(TheApp->GetBrowser()))
527 #endif
528 wIter->item()->Stop();
529 }
530 #ifdef HAVE_AFLOCK
531 stopTrackers();
532 #endif
533 char wrlpath[1024] = { 0 };
534 if (swBrowserGetVrmlLevel(GetBrowser()) & XITE) {
535 mystrncpy_secure(wrlpath, SaveTempFile(scene, ".dune_preview",
536 PURE_X3DV), 1024);
537 #ifdef _WIN32
538 char posixPath[1024] = { 0 };
539 // X_ITE nneds posix path
540 toPosixPath(posixPath, wrlpath, 1024);
541 mystrncpy_secure(wrlpath, posixPath, 1024);
542 #endif
543 }
544
545 int oldWriteFlags = scene->getWriteFlags();
546 int newVrmlLevel = swBrowserGetVrmlLevel(TheApp->GetBrowser());
547 int newWriteFlags = scene->getWriteFlags();
548 if (swBrowserGetVrmlLevel(GetBrowser()) & X3DOM) {
549 newVrmlLevel = X3DOM;
550 scene->setWriteFlags(X3DOM);
551 }
552 newWriteFlags |= newVrmlLevel;
553
554 #ifndef _WIN32
555 if (!swBrowserGetUseFork(TheApp->GetBrowser())) {
556
557 swHideWindow(m_mainWnd);
558 // swIconifyWindow(m_mainWnd);
559 swDisableTimers();
560 }
561 #endif
562 const char *textEditCommand;
563 const char *textEditLinenumberOption;
564 int textEditUseExtensionTxt;
565 swTextEditGetSettings(m_textedit,
566 &textEditCommand, &textEditLinenumberOption,
567 &textEditUseExtensionTxt);
568 saveTempFiles(m_currentWindow, textEditUseExtensionTxt);
569
570 scene->setWriteFlags(newWriteFlags);
571 char *temppath = SaveTempFile(scene, ".dune_preview",
572 newVrmlLevel,
573 wrlpath[0] ? wrlpath : NULL);
574 scene->setWriteFlags(oldWriteFlags);
575
576 const char *command;
577 int vrmlLevel;
578 int useRemote;
579 int xtypExecuteOrFork;
580 const char *remoteCommand;
581 const char *application;
582 const char *topic;
583
584 swBrowserGetSettings(GetBrowser(), &command,
585 &vrmlLevel, &useRemote, &xtypExecuteOrFork,
586 &remoteCommand, &application, &topic);
587
588 const char *command2 = strdup(command);
589 const char *remoteCommand2 = strdup(remoteCommand);
590
591 int oldVrmlLevel = vrmlLevel;
592 bool resetBrowserType = false;
593 if (strlen(temppath) != 0) {
594 int remote = swBrowserGetRemote(GetBrowser());
595 if (swBrowserGetVrmlLevel(GetBrowser()) & X3DOM) {
596 swBrowserSetRemote(GetBrowser(), 1);
597 #ifdef _WIN32
598 remote = true;
599 swBrowserSetRemote(GetBrowser(), remote);
600 #endif
601 }
602 if (swBrowserGetVrmlLevel(GetBrowser()) & XITE) {
603 swBrowserSetRemote(GetBrowser(), 1);
604 #ifdef _WIN32
605 remote = true;
606 swBrowserSetRemote(GetBrowser(), remote);
607 #endif
608 }
609
610 scene->setWriteFlags(newWriteFlags);
611 #ifdef _WIN32
612 MyString path = "";
613 path += "file://";
614 path += temppath;
615 swBrowserPreview(GetBrowser(), path, m_mainWnd);
616 #else
617 swBrowserPreview(GetBrowser(), temppath, m_mainWnd);
618 #endif
619 scene->setWriteFlags(oldWriteFlags);
620 }
621 #ifdef HAVE_AFLOCK
622 restartTrackers();
623 #endif
624 #ifndef _WIN32
625 if (!swBrowserGetUseFork(TheApp->GetBrowser())) {
626 // swDeIconifyWindow(m_mainWnd);
627 restoreTempFiles();
628 swEnableTimers();
629 }
630 #else
631 restoreTempFiles();
632 #endif
633 if (resetBrowserType) {
634 int dummy;
635 swBrowserSetSettings(GetBrowser(), command2,
636 oldVrmlLevel, useRemote, xtypExecuteOrFork,
637 remoteCommand2, application, topic);
638 }
639 }
640
641 void
642 DuneApp::OnFileUpload(Scene* scene)
643 {
644 char *temppath = SaveTempFile(scene,".dune_upload",
645 swBrowserGetVrmlLevel(TheApp->GetBrowser()));
646 char *htmlpath = (char *)"";
647 if (strlen(temppath) != 0) {
648 htmlpath = swUpload(m_upload, temppath, m_helpBrowser, m_mainWnd);
649 }
650 if (strlen(htmlpath) != 0)
651 AddToFilesToDelete(htmlpath);
652 }
653
654 class PathInt
655 {
656 public:
657 int *path;
658 int len;
659 PathInt(int *p, int l) {
660 path = p;
661 len = l;
662 }
663 };
664
665
666 void DuneApp::saveTempPath(Scene* scene)
667 {
668 if (scene->getSelection()) {
669 PathInt *pathInt = new PathInt(scene->getSelection()->copyPathInt(),
670 scene->getSelection()->getPathLen());
671 m_tempPath.append(pathInt);
672 }
673 }
674
675 void DuneApp::restoreTempPath(Scene* scene, int i)
676 {
677 if (m_tempPath[i]) {
678 scene->setSelection(new Path(m_tempPath[i]->path,
679 m_tempPath[i]->len, scene));
680 delete [] m_tempPath[i]->path;
681 delete m_tempPath[i];
682 m_tempPath[i] = NULL;
683 }
684 }
685
686
687 #ifndef HAVE_OPEN_IN_NEW_WINDOW
688
689 // save VRML files (with .wrl/.x3dv or .txt extension) into a list of
690 // temporary files and hide the windows (to call a editor next)
691 // the file of the currentWindow is first stored in the list
692
693 bool
694 DuneApp::saveTempFiles(MainWindow *currentWindow, int useExtensionTxt)
695 {
696 m_tempPath.resize(0);
697 m_tempFiles.Init();
698 int count = 0;
699 List<MainWindow *>::Iterator *wIter;
700 for (wIter = m_windows.first(); wIter != NULL; wIter = wIter->next()) {
701 Scene *scene = wIter->item()->GetScene();
702 URL oldURL = scene->getURL();
703 char* oldPath = mystrdup(scene->downloadPath(oldURL));
704
705 char filename[1024] = { 0 };
706 mysnprintf(filename,1024,"%s_%d",".dune_textedit",count++);
707 char *savefile = (char *)malloc(1024);
708 if (!useExtensionTxt)
709 if (scene->isX3d())
710 swGetTempFile(savefile, filename, ".x3dv", 1024);
711 else
712 swGetTempFile(savefile, filename, ".wrl", 1024);
713 else
714 swGetTempFile(savefile, filename, ".txt", 1024);
715
716 URL url(oldPath, savefile);
717
718 // is file writable ?
719 int f = open(url.GetPath(), O_WRONLY | O_CREAT,00666);
720 if (f == -1) {
721 if (!useExtensionTxt)
722 if (scene->isX3d())
723 swGetTempPath(savefile, filename, ".x3dv", 1024);
724 else
725 swGetTempPath(savefile,filename,".wrl",1024);
726 else
727 swGetTempPath(savefile,filename,".txt",1024);
728 f = open(savefile, O_WRONLY | O_CREAT,00666);
729 if (f == -1) {
730 char errorstring1[256];
731 swLoadString(IDS_SAVE_EDIT_ERROR1, errorstring1, 255);
732 char errorstring2[256];
733 swLoadString(IDS_SAVE_EDIT_ERROR2, errorstring2, 255);
734 char msg[1024];
735 mysnprintf(msg, 1023, errorstring1, savefile,
736 strerror(errno), errorstring2);
737 TheApp->MessageBox(msg);
738 return false;
739 }
740 }
741 AddToFilesToDelete(savefile);
742 close(f);
743
744 if (wIter->item() == currentWindow)
745 initSelectionLinenumber();
746 bool oldKeepUrls = TheApp->GetKeepURLs();
747 TheApp->SetKeepURLs(true);
748 int writeFlags = TEMP_SAVE | SKIP_SAVED_TEST;
749 if (scene->getStoreAsHtml())
750 writeFlags |= X3D_XML | X3DOM;
751 else if (scene->isX3d())
752 writeFlags |= X3DV;
753 const char *file = url.GetPath();
754 if (wIter->item()->SaveFile(file, savefile, writeFlags)) {
755 saveTempPath(wIter->item()->GetScene());
756 TheApp->removeClipboardNode(getClipboardNode());
757 if ((currentWindow != NULL) && (wIter->item() == currentWindow))
758 m_tempFiles.insert(new FileBackup(file, oldURL, oldPath));
759 else
760 m_tempFiles.append(new FileBackup(file, oldURL, oldPath));
761 // hide and remove window
762 swHideWindow(wIter->item()->getParentWindow());
763 } else {
764 // save failed, need to restore...
765 return false;
766 }
767 TheApp->SetKeepURLs(oldKeepUrls);
768 #ifndef _WIN32
769 free(oldPath);
770 #endif
771 }
772 // deleting from a shrinking List is not trivial...
773 wIter = m_windows.first();
774 while (wIter != NULL) {
775 MainWindow *windowToDelete = wIter->item();
776 wIter = wIter->next();
777 if (windowToDelete != NULL) {
778 windowToDelete->destroyMainWindow();
779 m_windows.remove(m_windows.find(windowToDelete));
780 // fix me delete windowToDelete;
781 }
782 }
783 swUpdate();
784 return true;
785 }
786
787 static bool checkLinenumberOption(const char *linenumberOption)
788 {
789 bool hasLinenumberOption = (linenumberOption[0] != 0);
790
791 // check if linenumber option only contain blanks
792 if (hasLinenumberOption) {
793 hasLinenumberOption = false;
794 for (unsigned int i = 0; i < strlen(linenumberOption); i++)
795 if (linenumberOption[i] != ' ')
796 hasLinenumberOption = true;
797 }
798 return hasLinenumberOption;
799 }
800
801
802 void
803 DuneApp::restoreTempFiles(void)
804 {
805 List<FileBackup *>::Iterator *fIter = m_tempFiles.first();
806 for (int i = 0; i < m_tempFiles.size(); i++) {
807 Scene *scene = new Scene();
808 forgetClipBoardNode();
809 forgetNameTranslation();
810 bool error = false;
811 do {
812 newMainWnd(m_mainWnd);
813 URL url(fIter->item()->m_url.GetPath(),
814 fIter->item()->m_backupFile);
815 if (ImportFile(url.GetPath(), scene)) {
816 scene->setExtraModifiedFlag();
817 scene->setURL(fIter->item()->m_url);
818 MyString path = fIter->item()->m_url.ToPath();
819 scene->setPath(path);
820 MainWindow *newwindow = new MainWindow(scene, m_mainWnd);
821 m_windows.append(newwindow);
822 error = false;
823 } else {
824 error = true;
825 checkAndRepairTextEditCommand();
826
827 const char *textEditCommand;
828 const char *textEditLinenumberOption;
829 int textEditUseExtensionTxt;
830
831 swTextEditGetSettings(m_textedit,
832 &textEditCommand,
833 &textEditLinenumberOption,
834 &textEditUseExtensionTxt);
835
836 MyString command = mystrdup(textEditCommand);
837 if (checkLinenumberOption(textEditLinenumberOption)) {
838 command += " ";
839 command += mystrdup(textEditLinenumberOption);
840 char number[1024];
841 mysnprintf(number, 1023, "%d", scene->getErrorLineNumber());
842 command += number;
843 }
844 command += " ";
845 command += fIter->item()->m_backupFile;
846 swHideWindow(m_mainWnd);
847 swUpdate();
848 delete scene;
849 scene = new Scene();
850 if (system((const char*)command) != 0) {
851 fprintf(stderr, "failed: %s\n", (const char*)command);
852 }
853 }
854 } while (error);
855 fIter = fIter->next();
856 scene->findBindableNodes();
857 UpdateAllWindows();
858 restoreTempPath(scene, i);
859 scene->UpdateViews(NULL, UPDATE_SELECTION);
860 }
861 }
862
863 void
864 DuneApp::OnFileEdit(MainWindow *window, Scene* oldScene, char* filename)
865 {
866 checkAndRepairTextEditCommand();
867
868 const char *TextEditCommand;
869 const char *TextEditLinenumberOption;
870 int TextEditUseExtensionTxt;
871
872 swTextEditGetSettings(m_textedit,
873 &TextEditCommand, &TextEditLinenumberOption,
874 &TextEditUseExtensionTxt);
875
876 swDisableTimers();
877
878 bool saveSuccess = saveTempFiles(window, TextEditUseExtensionTxt);
879
880 MyString command = mystrdup(TextEditCommand);
881
882 if (checkLinenumberOption(TextEditLinenumberOption)) {
883 command += " ";
884 command += mystrdup(TextEditLinenumberOption);
885 char number[1024];
886 mysnprintf(number, 1023, "%d", getSelectionLinenumber());
887 command += number;
888 }
889
890 SavePreferences();
891
892 if (filename == NULL) {
893 List<FileBackup *>::Iterator *fIter = m_tempFiles.first();
894 for (int i = 0; i < m_tempFiles.size(); i++) {
895 command += " ";
896 command += fIter->item()->m_backupFile;
897 fIter = fIter->next();
898 }
899 } else {
900 command += " ";
901 command += filename;
902 }
903
904 bool commandFailed = false;
905 swHideWindow(m_mainWnd);
906 swUpdate();
907 if (saveSuccess)
908 if (system((const char*)command) != 0)
909 commandFailed = true;
910 swDestroyWindow(m_mainWnd);
911 swEnableTimers();
912 newMainWnd(m_mainWnd);
913 if (!saveSuccess) {
914 char errorstring[256];
915 swLoadString(IDS_SAVE_FAILED, errorstring, 255);
916 TheApp->MessageBoxPerror(errorstring);
917 }
918 if (commandFailed)
919 TheApp->MessageBoxId(IDS_EDIT_COMMAND_ERROR);
920 restoreTempFiles();
921 }
922 #endif
923
924 bool
925 DuneApp::AddFile(char* openpath, Scene* scene)
926 {
927 if (!TheApp->ImportFile(openpath, scene)) {
928 delete scene;
929 return false;
930 }
931 return true;
932 }
933
934 bool
935 DuneApp::ImportFile(const char *openpath, Scene* scene, Node *node, int field)
936 {
937 FILE *file;
938 char path1[1024];
939 char* filepath;
940
941 URL importURL(openpath);
942 setImportURL(openpath);
943 setImportFile(openpath);
944
945 MyString myPath;
946 if (!scene->Download(importURL, &myPath))
947 return false;
948
949 mystrncpy_secure(path1, myPath, 1024);
950 filepath = swKillFileQuotes(path1);
951 if (strcmp(filepath, "-") == 0)
952 file = stdin;
953 else if (!(file = fopen(filepath, "rb")))
954 return false;
955
956 scene->saveProtoStatus();
957
958 int undoStackTopBeforeParse = scene->getUndoStackTop();
959
960 const char *errors = scene->parse(file, node, field, SCAN_FOR_BOTH);
961 fclose(file);
962
963 importURL = scene->getURL();
964
965 scene->setSelection(scene->getRoot());
966 scene->UpdateViews(NULL, UPDATE_SELECTION);
967 scene->UpdateViews(NULL, UPDATE_ALL, NULL);
968
969 if (errors[0]) {
970 #ifdef _WIN32
971 swDebugf("%s", errors);
972 #endif
973 TheApp->MessageBox(errors);
974 // delete so far successful imported nodes on errors
975 while ((scene->getUndoStackTop() > undoStackTopBeforeParse) &&
976 scene->canUndo())
977 scene->undo();
978 scene->restoreProtoStatus();
979
980
981 return false;
982 }
983 return true;
984 }
985
986 bool
987 DuneApp::OpenFile(const char *openpath)
988 {
989 URL url;
990 url.FromPath(openpath);
991
992 forgetClipBoardNode();
993 forgetNameTranslation();
994
995 Scene *scene = new Scene();
996 scene->setURL(url);
997 scene->setPath(url.ToPath());
998
999 if (!ImportFile(openpath, scene)) {
1000 delete scene;
1001 return false;
1002 }
1003
1004 scene->findBindableNodes();
1005
1006 scene->setSelection(scene->getRoot());
1007 scene->UpdateViews(NULL, UPDATE_SELECTION);
1008 scene->UpdateViews(NULL, UPDATE_ALL);
1009 AddToRecentFiles(openpath);
1010
1011 // startCallback();
1012
1013 // create a new window for our new scene
1014 newMainWnd(m_mainWnd);
1015 MainWindow *window = new MainWindow(scene, m_mainWnd);
1016 m_windows.append(window);
1017
1018 UpdateAllWindows();
1019
1020 return true;
1021 }
1022
1023 void DuneApp::OnFileClose(MainWindow *window)
1024 {
1025
1026 if (!window->SaveModified()) {
1027 return;
1028 }
1029 List<MainWindow *>::Iterator *currentWindow = m_windows.find(window);
1030 SWND currentWnd = currentWindow->item()->getParentWindow();
1031 m_windows.remove(currentWindow);
1032 // MacOSX X11 can freeze here. Bug in X11 shutdown code ?
1033 #ifndef MACOSX
1034 delete window;
1035 #endif
1036 if (m_windows.size() == 0) {
1037 for (long j = 0; j < m_filesToDelete.size(); j++)
1038 swRemoveFile(*m_filesToDelete[j]);
1039 swUploadCleanupPasswd(m_upload);
1040 Exit();
1041 } else if (currentWnd == m_mainWnd) {
1042 m_mainWnd = m_windows.first()->item()->getParentWindow();
1043 }
1044 }
1045
1046 void DuneApp::OnFileExit()
1047 {
1048 List<MainWindow *>::Iterator *i;
1049 for (i = m_windows.first(); i; i = i->next()) {
1050 if (!i->item()->SaveModified()) return;
1051 }
1052 for (i = m_windows.first(); i; i = i->next()) {
1053 delete i->item();
1054 }
1055 for (long j = 0; j < m_filesToDelete.size(); j++)
1056 swRemoveFile(*m_filesToDelete[j]);
1057 swUploadCleanupPasswd(m_upload);
1058 Exit();
1059 }
1060
1061 void DuneApp::Exit()
1062 {
1063 SaveRecentFileList();
1064
1065 SavePreferences();
1066 swBrowserShutdown(m_browser);
1067 // do not delete m_prefs, cause there may be a crash in swExit 8-(
1068 // swDeletePreferences(m_prefs);
1069 setNormalExit();
1070 #ifdef MACOSX
1071 // needed to kill whitedune starter on MacOSX exit
1072 if (m_exitPid > 0) {
1073 kill(m_exitPid, 15);
1074 }
1075 #endif
1076 swExit();
1077 }
1078
1079 void DuneApp::UpdateAllWindows()
1080 {
1081 for (List<MainWindow *>::Iterator *i = m_windows.first(); i; i = i->next())
1082 i->item()->GetScene()->UpdateViews(NULL, UPDATE_ALL);
1083 }
1084
1085 int
1086 DuneApp::GetNumRecentFiles() const
1087 {
1088 return m_recentFiles.size();
1089 }
1090
1091 const MyString &
1092 DuneApp::GetRecentFile(int index) const
1093 {
1094 return m_recentFiles[index];
1095 }
1096
1097 void
1098 DuneApp::AddToRecentFiles(const MyString &filename)
1099 {
1100 int i = m_recentFiles.find(filename);
1101
1102 if (i >= 0) {
1103 m_recentFiles.remove(i);
1104 }
1105 int n = MIN(m_recentFiles.size(), MAX_RECENT_FILES-1);
1106 for (i = n; i > 0; i--) {
1107 m_recentFiles[i] = "";
1108 m_recentFiles[i] = m_recentFiles[i-1];
1109 }
1110 m_recentFiles[0] = filename;
1111 }
1112
1113 void
1114 DuneApp::AddToFilesToDelete(char* string)
1115 {
1116 // test if string is already in list
1117 for (long i = 0; i < m_filesToDelete.size(); i++)
1118 if (strcmp(string,(char*) m_filesToDelete[i])==0)
1119 return;
1120 m_filesToDelete.append(new MyString(string));
1121 }
1122
1123 void
1124 DuneApp::initSelectionLinenumber(void)
1125 {
1126 m_selectionLinenumberFlag = false;
1127 m_selectionLinenumber = 1;
1128 }
1129
1130 void
1131 DuneApp::checkSelectionLinenumberCounting(Scene* scene, Node* node)
1132 {
1133 if (scene->getSelection()->getNode() == node)
1134 m_selectionLinenumberFlag = true;
1135 }
1136
1137 void
1138 DuneApp::incSelectionLinenumber(int increment)
1139 {
1140 if (!m_selectionLinenumberFlag)
1141 m_selectionLinenumber += increment;
1142 }
1143
1144 int
1145 DuneApp::getSelectionLinenumber(void)
1146 {
1147 if (m_selectionLinenumberFlag)
1148 return m_selectionLinenumber;
1149 else
1150 return 1;
1151 }
1152
1153 void
1154 DuneApp::reOpenWindow(Scene* scene)
1155 {
1156 #ifndef HAVE_OPEN_IN_NEW_WINDOW
1157 newMainWnd(m_mainWnd);
1158 MainWindow *window = new MainWindow(scene, m_mainWnd);
1159 m_windows.append(window);
1160 TheApp->deleteOldWindow();
1161 #endif
1162 }
1163
1164 bool
1165 DuneApp::checkSaveOldWindow(void)
1166 {
1167 // give user a chance to save first
1168 List<MainWindow *>::Iterator *curWinItr = m_windows.last();
1169 m_currentWindow = curWinItr->item();
1170 if (curWinItr != NULL) {
1171 if (curWinItr->item() != NULL)
1172 if (!curWinItr->item()->SaveModified())
1173 return false;
1174 SavePreferences();
1175 }
1176 return true;
1177 }
1178
1179 void
1180 DuneApp::deleteOldWindow(void)
1181 {
1182 // delete the old window
1183 List<MainWindow *>::Iterator *curWinItr = NULL;
1184 for (List<MainWindow *>::Iterator *WinItr = m_windows.first(); WinItr;
1185 WinItr = WinItr->next())
1186 if (WinItr->item() == m_currentWindow) {
1187 curWinItr = WinItr;
1188 m_currentWindow = NULL;
1189 break;
1190 }
1191 if (curWinItr != NULL) {
1192 if (curWinItr->item() != NULL)
1193 delete curWinItr->item();
1194 m_windows.remove(curWinItr);
1195 }
1196 }
1197
1198 bool
1199 DuneApp::hasUpload(void)
1200 {
1201 return swHasUpload(m_upload);
1202 }
1203
1204 void
1205 DuneApp::addToProtoLibrary(char* category, char* protoFile)
1206 {
1207 // search for a free key
1208 for (int i=1; i<1000; i++) {
1209 char key[1024];
1210 mysnprintf(key, 1023, "%s%d", m_keyProtoFile, i);
1211 const char *value = GetPreference(key, "");
1212 if (strlen(value) == 0) {
1213 SetPreference(key, protoFile);
1214 mysnprintf(key, 1023, "%s%d", m_keyProtoCategory, i);
1215 SetPreference(key,category);
1216 break;
1217 }
1218 }
1219 }
1220
1221 bool
1222 DuneApp::readProtoLibrary(Scene* scene)
1223 {
1224 m_importingProtoLibrary = true;
1225 for (int i=1; i<1000; i++) {
1226 char key[1024];
1227 mysnprintf(key, 1023, "%s%d", m_keyProtoFile, i);
1228 const char *value = GetPreference(key, "");
1229 if (strlen(value) != 0) {
1230 if (!ImportFile(value, scene)) {
1231 m_importingProtoLibrary = false;
1232 return false;
1233 }
1234 }
1235 }
1236 m_importingProtoLibrary = false;
1237 return true;
1238 }
1239
1240 bool
1241 DuneApp::loadNewInline()
1242 {
1243 if (m_numberLoadedInlines > GetMaxInlinesToLoad())
1244 return false;
1245 m_numberLoadedInlines++;
1246 return true;
1247 }
1248
1249 bool DuneApp::browseCommand(char *buf, int len, int ids_text)
1250 {
1251 buf[0] = 0;
1252 SWND wnd = mainWnd();
1253 char prompt[256];
1254
1255 swLoadString(ids_text + swGetLang(), prompt, 255);
1256 #ifdef _WIN32
1257 const char *choice = "executable (*.exe, *.com, *.bat)\0*.exe;*.com;*.bat\0All Files (*.*)\0*.*\0\0";
1258 #else
1259 const char *choice = "executable (*)\0*;\0\0";
1260 #endif
1261 return swOpenExecutableDialog(wnd, prompt, choice, buf, len);
1262 }
1263
1264 bool DuneApp::checkCommand(const char *oldCommand, bool checkForFile)
1265 {
1266 bool ret = true;
1267 bool checkFile = checkForFile;
1268 #ifdef _WIN32
1269 checkFile = true;
1270 #endif
1271
1272 if (strlen(oldCommand) == 0)
1273 return false;
1274
1275 // isolate first command and check for \ or /
1276 char *command = new char[strlen(oldCommand) + 1];
1277 strcpy(command, oldCommand);
1278 char *file = command;
1279 bool hasPathSeperator = false;
1280 bool hasQuote = false;
1281 bool isInString = false;
1282 for (unsigned int i = 0; i < strlen(command); i++)
1283 if ((command[i] == '/') || (command[i] == '\\'))
1284 hasPathSeperator = true;
1285 else if (command[i] == '"') {
1286 isInString = !isInString;
1287 hasQuote = true;
1288 } else if ((command[i] == ' ') && !isInString) {
1289 command[i] = 0;
1290 break;
1291 }
1292
1293 // return if there is no path seperator
1294 if (checkFile)
1295 if (!hasPathSeperator) {
1296 delete [] command;
1297 return false;
1298 }
1299
1300 // strip "s from file
1301 if (hasQuote) {
1302 file = command + 1;
1303 if (file[strlen(file) - 1] == '"')
1304 file[strlen(file) - 1] = 0;
1305 }
1306
1307 if (checkFile) {
1308 // return if first command is not a file
1309 struct stat fileStat;
1310 if ((stat(file, &fileStat) == 0) && S_ISREG(fileStat.st_mode))
1311 ret = true;
1312 else
1313 ret = false;
1314 }
1315 delete [] command;
1316 return ret;
1317 }
1318
1319 void DuneApp::checkAndRepairTextEditCommand(void)
1320 {
1321 const char *textEditCommand;
1322 const char *textEditLinenumberOption;
1323 int textEditUseExtensionTxt;
1324
1325 while (1) {
1326 swTextEditGetSettings(TheApp->GetTextedit(),
1327 &textEditCommand, &textEditLinenumberOption,
1328 &textEditUseExtensionTxt);
1329 if (checkCommand(textEditCommand))
1330 break;
1331 TheApp->MessageBoxId(IDS_TEXTEDIT_PROMPT);
1332 TexteditSettingsDialog dlg(m_mainWnd);
1333 dlg.DoModal();
1334 }
1335 }
1336
1337 void DuneApp::checkAndRepairImageEditCommand(void)
1338 {
1339 const char *imageEditCommand;
1340
1341 while (1) {
1342 imageEditCommand = swImageEditGetSettings(TheApp->GetTextedit());
1343 if (checkCommand(imageEditCommand))
1344 break;
1345 TheApp->MessageBoxId(IDS_IMAGEEDIT_PROMPT);
1346 TexteditSettingsDialog dlg(m_mainWnd);
1347 dlg.DoModal();
1348 }
1349 }
1350
1351 void DuneApp::checkAndRepairImageEdit4KidsCommand(void)
1352 {
1353 const char *imageEditCommand;
1354
1355 while (1) {
1356 imageEditCommand = swImageEdit4KidsGetSettings(TheApp->GetTextedit());
1357 if (checkCommand(imageEditCommand))
1358 break;
1359 TheApp->MessageBoxId(IDS_IMAGEEDIT4KIDS_PROMPT);
1360 TexteditSettingsDialog dlg(m_mainWnd);
1361 dlg.DoModal();
1362 }
1363 }
1364
1365 void DuneApp::checkAndRepairSoundEditCommand(void)
1366 {
1367 const char *soundEditCommand;
1368
1369 while (1) {
1370 soundEditCommand = swSoundEditGetSettings(TheApp->GetTextedit());
1371 if (checkCommand(soundEditCommand))
1372 break;
1373 TheApp->MessageBoxId(IDS_SOUNDEDIT_PROMPT);
1374 TexteditSettingsDialog dlg(m_mainWnd);
1375 dlg.DoModal();
1376 }
1377 }
1378
1379 void DuneApp::checkAndRepairMovieEditCommand(void)
1380 {
1381 const char *movieEditCommand;
1382
1383 while (1) {
1384 movieEditCommand = swMovieEditGetSettings(TheApp->GetTextedit());
1385 if (checkCommand(movieEditCommand))
1386 break;
1387 TheApp->MessageBoxId(IDS_MOVIEEDIT_PROMPT);
1388 TexteditSettingsDialog dlg(m_mainWnd);
1389 dlg.DoModal();
1390 }
1391 }
1392
1393 int
1394 DuneApp::printRenderErrors(bool printOnOutOfMemory)
1395 {
1396 GLenum error = glGetError();
1397 bool printError = (error != GL_NO_ERROR);
1398 if (printError)
1399 if ((!printOnOutOfMemory) && (error == GL_OUT_OF_MEMORY))
1400 printError = false;
1401 if (printError)
1402 printRenderErrors(error);
1403 return error;
1404 }
1405
1406 void
1407 DuneApp::printRenderErrors(GLenum error)
1408 {
1409 if (error != GL_NO_ERROR) {
1410 if (m_glErrorCount < TheApp->GetX11ErrorsLimit())
1411 printf("%s\n",(const char *)gluErrorString(error));
1412 m_glErrorCount++;
1413 }
1414 }
1415
1416 int
1417 DuneApp::searchIllegalChar(char *id)
1418 {
1419 int invalidCharPosition = -1;
1420 // see Annex A.3 of ISO-19776
1421 static const int illegalFirstChars[13] =
1422 {
1423 0x22, 0x23, 0x27, 0x2b, 0x2c, 0x2d, 0x2e,
1424 0x5b, 0x5c, 0x5d,
1425 0x7b, 0x7d, 0x7f
1426 };
1427 static const int illegalChars[11] =
1428 {
1429 0x22, 0x23, 0x27, 0x2c, 0x2e,
1430 0x5b, 0x5c, 0x5d,
1431 0x7b, 0x7d, 0x7f
1432 };
1433 if (!isalpha(id[0])) {
1434 if (isdigit(id[0]))
1435 invalidCharPosition = 0;
1436 else
1437 if ((id[0] > 0) && (id[0] <= 0x20))
1438 invalidCharPosition = 0;
1439 else
1440 for (unsigned int j = 0;
1441 j < sizeof(illegalFirstChars)/sizeof(int); j++)
1442 if (id[0] == illegalFirstChars[j]) {
1443 invalidCharPosition = 0;
1444 break;
1445 }
1446 }
1447 if (invalidCharPosition == -1)
1448 for (unsigned int i = 1; i < strlen(id); i++)
1449 if ((!isalnum(id[i])) && (!isdigit(id[i]))) {
1450 if ((id[i] > 0) && (id[i] <= 0x20))
1451 invalidCharPosition = i;
1452 else
1453 for (unsigned int j = 0;
1454 j < sizeof(illegalChars)/sizeof(int); j++)
1455 if (id[i] == illegalChars[j]) {
1456 invalidCharPosition = i;
1457 break;
1458 }
1459 }
1460 return invalidCharPosition;
1461 }
1462
1463
1464 void
1465 DuneApp::interact(void)
1466 {
1467 if (m_timeOut > 0) {
1468 m_lastInteraction = time(NULL);
1469 m_timeOutSet = false;
1470 }
1471 }
1472
1473 bool
1474 DuneApp::timeOut(void)
1475 {
1476 // if (m_timeOutSet)
1477 // return true;
1478 if ((time(NULL) - m_lastInteraction) >= m_timeOut) {
1479 m_timeOutSet = true;
1480 // set selection to root of screengraph on timeout
1481 List<MainWindow *>::Iterator *wIter;
1482 for (wIter = m_windows.first(); wIter != NULL; wIter = wIter ->next()) {
1483 Scene *scene = wIter->item()->GetScene();
1484 scene->setSelection(scene->getRoot());
1485 if (!scene->isRunning())
1486 wIter->item()->Play();
1487 scene->UpdateViews(NULL, UPDATE_SELECTION);
1488 }
1489 return true;
1490 }
1491 return false;
1492 }
1493
1494 void
1495 DuneApp::endTrackAnimation(void)
1496 {
1497 m_trackAnimation = false;
1498 List<MainWindow *>::Iterator *wIter;
1499 for (wIter = m_windows.first(); wIter != NULL; wIter = wIter ->next()) {
1500 Scene *scene = wIter->item()->GetScene();
1501 if (scene->isRunning() && scene->isRecording())
1502 m_trackAnimation = true;
1503 }
1504 }
1505
1506 FileBackup::FileBackup(const char* backupFile, URL url, const char* path)
1507 {
1508 m_backupFile = "";
1509 m_backupFile += backupFile;
1510
1511 m_url = url;
1512
1513 m_path = "";
1514 m_path += path;
1515 }
1516
1517