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