Back

1     // KERNEL
2     // * allow " or ' as escape chars, define able one for each (character/string)
3     // * parse single/multi line comment strings: exception handling
4     // * make " defineable as symbol
5     // * think about "CharsWithinString" -> identify identifier without this option!!
6     //   ... or make word list matching with whole string
7
8     // Future:
9     // * Option: generate output using style sheets (css)
10    // * Option: add line anchors
11
12
13    //------------------------------------------------------------------------------
14    // Module: FMain.cpp                                                          //
15    //                                                                            //
16    //    Main program of Lore's Source to HTML Converter                         //
17    //                                                                            //
18    //    Copyright (c) 2000-2004 by Lars Haendel                                 //
19    //    Home: http://www.newty.de                                               //
20    //                                                                            //
21    //    This program is free software and can be used under the terms of the    //
22    //    GNU licence. See header-file for further information and disclaimer.    //
23    //                                                                            //
24    //------------------------------------------------------------------------------
25
26
27
28    #include <vcl.h>
29    #pragma hdrstop
30
31    #pragma package(smart_init)
32    #pragma resource "*.dfm"
33
34
35    //----------------------------------------------------------------------------------------------------------------------
36    #include <FileCtrl.hpp>                // due to:  MinimizeName
37    #include <stdio>                       //          sprintf
38    #include <process>                     //          _beginthread
39    #include <iostream>                    //          ifstream ...
40
41    #include "FMain.h"
42    #include "ThrConvert.h"                //          thread class for converting
43    #include "Conv2HTML.h"                 //          TConv2HTML
44    #include "ErrText.h"                   //          TErrText
45    #include "defines.h"                   //          defines like using namspace etc.
46
47
48    //----------------------------------------------------------------------------------------------------------------------
49    // program's registry keys, filenames ...
50    #define SZ_REGISTRY_KEY          "Source2HTML"                    // program's registry keys
51    #define SZ_ICON_FILE             "Source2HTML.ico"
52    #define SZ_INITIALIZED           "Initialized"
53    #define SZ_PROJECT_DIR           "Default project directory"
54    #define SZ_SOURCE_DIR            "Default source directory"
55    #define SZ_OUTPUT_DIR            "Default output directory"
56    #define SZ_INCLUDE_DIR           "Default include directory"
57    #define SZ_HELP_FILE             "Source2HTML.hlp"                // name of help file
58    #define INI_FILENAME             "Source2HTML.ini"                // name of ini file
59    #define STYLE_FILENAME           "Styles.ini"                     // name of style file
60    #define LANGUAGE_FILENAME1       "Languages.ini"                  // name of language definition file
61    #define LANGUAGE_FILENAME2       "Languages.log"                  // backup
62    #define SZ_OVERVIEW_FILE         "Overview.html"                  // name of generated overview file
63    #define PROJECT_EXTENSION        "lsc"                            // project file extension
64    #define SZ_DEF_STYLE_NAME        "User Defined"                   // default filename when saving style
65    #define SZ_SAVE_WARNING          "Not all styles were loaded. Saving overwrites style file. \
66    Some styles may be lost!! Save style file?"
67
68
69    //----------------------------------------------------------------------------------------------------------------------
70    // file filters
71    #define FILE_FILTER_HTML   "HTML files (*.html)|*.html|Any file (*.*)|*.*"
72
73
74    //----------------------------------------------------------------------------------------------------------------------
75    // Misc.
76    #define MAX_MESSAGES_IN_LISTVIEW 150         // max. number messages shown in list view
77
78
79    //----------------------------------------------------------------------------------------------------------------------
80    // globals
81    static char szCmdLine[STS];
82    char* GetCmdLine() { return szCmdLine; }           // command line
83
84
85    //----------------------------------------------------------------------------------------------------------------------
86    // Utility function: Interpret character as hex and convert it to int
87    int Hex2Int(const char& c)
88    {
89       if(IsDigit(c))
90          return (int) c-48;      // number 0..9
91
92       if(c>96)
93          return (int) c-87;      // lower case letter a..f
94       else
95          return (int) c-55;      // capital letter A..F
96    }
97
98
99    //----------------------------------------------------------------------------------------------------------------------
100   // Utility function: Convert color string to TColor
101   inline TColor StringToTColor(const char*const& szColor)
102   {
103      return TColor(RGB(Hex2Int(szColor[1])*16+Hex2Int(szColor[2]), Hex2Int(szColor[3])*16+Hex2Int(szColor[4])
104                     , Hex2Int(szColor[5])*16+Hex2Int(szColor[6])));
105   }
106
107
108
109   TFMain *FMain;
110   //----------------------------------------------------------------------------------------------------------------------
111   // constructor
112   __fastcall TFMain::TFMain(TComponent* Owner) : TForm(Owner)
113   {
114      // a) compose and set window caption
115      Caption = szCmplPrgName = AnsiString(SZ_PRGNAME) + " " + AnsiString(SZ_VERSION);
116
117      // b) set style, registry and language to NULL    Note: Ini is done in OnShow()
118      style = NULL;
119      registry = NULL;
120      lang = NULL;
121
122      // c) store directory of the executable, clear project filename and set help filename
123      szDir = IncludeTrailingBackslash(ExtractFileDir(Application->ExeName));
124      szProjectFile = "";                                                        // clear
125      Application->HelpFile = szDir + SZ_HELP_FILE;
126
127      // d) set flags
128      f_Converting = f_ManipCtrls = false;
129      f_Saved = true;
130
131      /* rest of initialization is done in OnShow() */
132   }
133
134
135   //----------------------------------------------------------------------------------------------------------------------
136   // destructor
137   __fastcall TFMain::~TFMain()
138   {
139      delete registry;              // registry
140   };
141
142
143   //----------------------------------------------------------------------------------------------------------------------
144   // Called when user tries to close the main form: If conversion process is running, ask user before closing.
145   void __fastcall TFMain::OnCloseQuery(TObject*, bool &CanClose)
146   {
147      // a) ask user if program is busy
148      if(f_Converting)
149         if(f_Stop)
150         {
151            if(Application->MessageBox("Enforce \
152   termination ??", "Process should terminate but doesn't do so!", MB_YESNO | MB_ICONQUESTION)== ID_NO)
153               CanClose = false;
154         }
155         else
156            if(Application->MessageBox("Terminate it anyway ??", "Process still running!", MB_YESNO | MB_ICONQUESTION)== ID_YES)
157            {
158               CanClose = false;
159               f_Stop   = true;
160            }
161
162      // b) ask user if project is unsaved and there is at least one file specified
163      if(!f_Saved && project.nFiles()>0)
164         if(Application->MessageBox("Project not saved!! Save it now ??", "Question", MB_YESNO | MB_ICONQUESTION)==ID_YES)
165            TbSaveProjectClick(this);
166
167
168      // c) write default directories to registry
169      try
170      {
171         registry->OpenKey(AnsiString("\\Software\\") + SZ_REGISTRY_KEY, true);  // open key
172         registry->WriteString(SZ_PROJECT_DIR, szProjectDir);
173         registry->WriteString(SZ_SOURCE_DIR, szSourceDir);
174         registry->WriteString(SZ_OUTPUT_DIR, szOutputDir);
175         registry->WriteString(SZ_INCLUDE_DIR, szIncludeDir);
176         registry->CloseKey();                                                   // close key
177      }
178      catch(ERegistryException& err)   // exception handling
179
180      {
181         // Note: Should not happen cause access to subkeys of HKEY_CURRENT_USER should be given
182         Application->MessageBox("Should not happen for root key 'HKEY_CURRENT_USER'!!", "Error accessing registry !!"
183                                 , MB_OK | MB_ICONWARNING);
184      }
185   }
186
187
188   //----------------------------------------------------------------------------------------------------------------------
189   // Save style file using SaveStyles() when closing ...
190   void __fastcall TFMain::OnClose(TObject*, TCloseAction &Action) { SaveStyles(); }
191
192
193   //----------------------------------------------------------------------------------------------------------------------
194   // exit application
195   void __fastcall TFMain::MnExitClick(TObject*)
196   {
197      bool f_CanClose = true;
198      OnCloseQuery(this, f_CanClose);  // ask user if application is busy
199      if(f_CanClose)
200         Application->Terminate();
201   }
202
203
204   //----------------------------------------------------------------------------------------------------------------------
205   // Load styles from file, set the language sample texts, enable drag#&drop ...
206   void __fastcall TFMain::OnShow(TObject*)
207   {
208      //-------------------------------------------------------------------------------------------------------------------
209      // 1. create registry object and register project file extension if program is started first time
210      registry = new TRegistry;
211
212      try
213      {
214         registry->OpenKey(AnsiString("\\Software\\") + SZ_REGISTRY_KEY, true);     // open key
215         if(registry->ReadString(SZ_INITIALIZED).IsEmpty())                         // if data value 'Initialized is empty'
216         {
217            registry->CloseKey();                                                   // close key
218            int res = RegisterExtension();                                          // register extension
219            registry->RootKey = HKEY_CURRENT_USER;                                  // change root key back
220            registry->OpenKey(AnsiString("\\Software\\") + SZ_REGISTRY_KEY, true);  // open previous key again
221
222            // set 'Initialized' ...
223            if(res==ID_NO)                   // ... user decided NOT to register project file extension to me
224               registry->WriteString(SZ_INITIALIZED, "Extension NOT registered!");
225
226            if(res==ID_YES)                  // ... project file extension was registered
227               registry->WriteString(SZ_INITIALIZED, "Extension registered!");
228
229            if(res==-1)                      // ... error accessing registry
230               registry->WriteString(SZ_INITIALIZED, "Error accessing registry!");
231         }
232
233         // f) read default directories for projects, source files and output
234         szProjectDir = registry->ReadString(SZ_PROJECT_DIR);
235         szSourceDir  = registry->ReadString(SZ_SOURCE_DIR);
236         szOutputDir  = registry->ReadString(SZ_OUTPUT_DIR);
237         szIncludeDir = registry->ReadString(SZ_INCLUDE_DIR);
238         registry->CloseKey();                                // close key
239      }
240      catch(ERegistryException& err)   // exception handling
241      {
242         // Note: Should not happen cause access to subkeys of HKEY_CURRENT_USER should be given
243         AddMessage("Error accessing registry. Should not happen for root key 'HKEY_CURRENT_USER'!!");
244      }
245
246
247      //-------------------------------------------------------------------------------------------------------------------
248      // 2. load ini file
249
250      // a) try to load ini file and display message if an error occurs
251      try
252      {
253         // open file for output and check success
254         ifstream file((szDir + INI_FILENAME).c_str(), ios::in);
255         if(!file)
256            throw TErrText("Unable to open ini file: ", (szDir + INI_FILENAME).c_str());
257
258         defaults.Load(file);       // load ini file
259      }
260      catch(TErrText err)           // exception handling
261      {
262         // display error message
263         AddMessage(AnsiString("Error loading ini file! " ) + err.szErrText + " Using defaults!");
264
265         // reset to factory defaults
266         defaults.RestoreFactoryDefaults();
267
268         // try to create new ini file using SaveDefaults()
269         SaveDefaults();
270      }
271
272
273      //-------------------------------------------------------------------------------------------------------------------
274      // 3. load language definition file
275
276      // a) try to load language definition file and display message if an error occurs
277      try
278      {
279         // open file for output and check success
280         ifstream file((szDir + LANGUAGE_FILENAME1).c_str(), ios::in);
281         if(!file)
282            throw TErrText("Unable to open language definition file: ", (szDir + INI_FILENAME).c_str());
283
284         langs.Load(file);          // load language definition file
285      }
286      catch(TErrText err)           // exception handling
287      {
288         if(langs.Size()>0)         // display error in message list if at least one language definition was loaded ...
289         {
290            AddMessage(AnsiString("Error loading language definition file!"));
291            AddMessage(err.szErrText);
292            AddMessage("");
293         }
294
295         // ... else terminate program
296         else
297         {
298            Application->MessageBox(err.szErrText, "Fatal error loading language definitions! Program will terminate!"
299                                    , MB_OK | MB_ICONERROR);
300            Application->Terminate();  // terminate application
301         }
302      }
303
304      try
305      {
306         // open output file
307         ofstream file((szDir + LANGUAGE_FILENAME2).c_str(), ios::out);
308         if(!file)
309            throw TErrText("Unable to open log file for language definitions: ", (szDir + INI_FILENAME).c_str());
310
311         langs.Save(file);
312      }
313      catch(TErrText err)
314      {
315         // display error message
316         AddMessage(AnsiString("Error writing log of language definition file! ") + err.szErrText);
317      }
318
319      // initialize names in language drop down list
320      for(int i=0;i<langs.Size();i++)
321         CbLanguage->Items->Add(langs.Get(i)->Name());
322
323
324
325      //-------------------------------------------------------------------------------------------------------------------
326      // 4. load styles
327      f_StyleLoadError = false;
328
329      // a) try to load styles from style file and display message if an error occurs
330      try
331      {
332         styles.Load((szDir + STYLE_FILENAME).c_str());              // load style file
333      }
334      catch(TErrText err)
335      {
336         AddMessage(AnsiString("Error loading style file !! ") + err.szErrText);
337         f_StyleLoadError = true;                  // set flag: a warning will be displayed when saving style file
338      }
339
340      // b) transfer the names of each style to the list box
341      for(int i=0;i<styles.nStyles();i++)
342         LbStyles->Items->Add(styles.GetStyle(i)->szName);
343
344      // c) select style: if there are styles in the list, take the first one. Otherwise create temporary style object
345      InitializeStyle();
346
347
348
349      //-------------------------------------------------------------------------------------------------------------------
350      // 5. enable drag&drop and misc. settings
351      DragAcceptFiles(Handle, true);            // now the window receives WM_DROPFILES messages
352
353      PageControl->ActivePage = TsConvert;      // set active tab sheet
354      wrapper.hwnd = Handle;
355
356
357      //-------------------------------------------------------------------------------------------------------------------
358      // 6. open project if filename is passed in command line, else initialize to new project
359      char szCmdLine[STS];
360      strcpy(szCmdLine, GetCmdLine());                      // copy command line
361      if(szCmdLine[0]!='\0')                                // if not empty ...
362      {
363         // get first whitespace terminated string removing enclosing '"'
364         char* szString = szCmdLine;                        // ini
365         if(szCmdLine[0]=='"')
366            szString = &(szCmdLine[1]);                     // skip the '"' if necessary
367
368         int i=0;                                           // find terminating whitespace or '"'
369         while(!isspace(szString[i]) && szString[i]!='"')
370            i++;
371         szString[i]='\0';                                  // terminate string
372
373         OpenProject(ExpandFileName(szString).c_str());     // ... open project expanding relative filenames if necessary
374      }
375      else
376         MnNewProjectClick(this);                           // initialize new project
377   }
378
379
380   //----------------------------------------------------------------------------------------------------------------------
381   // register project file extension
382   int TFMain::RegisterExtension()
383   {
384      try
385      {
386         // a) change root key and generate extension string ('.lsc')
387         registry->RootKey = HKEY_CLASSES_ROOT;                                  // change root key
388         AnsiString szTmp = AnsiString(".") + PROJECT_EXTENSION;                 // extension string
389
390
391         // b) ask user if extension is already registered to another program
392         if(registry->KeyExists(szTmp))                                          // if extension key already exists
393         {
394            // read class registered to extension now
395            registry->OpenKey(szTmp, false);                                     // open key
396            AnsiString szOtherApp = registry->ReadString("");                    // read class asigned to extension
397            registry->CloseKey();                                                // close key again
398
399            // if ...
400            if(szOtherApp != SZ_REGISTRY_KEY)
401            {
402               // read command line registered to class
403               registry->OpenKey(AnsiString("\\") + szOtherApp + "\\shell\\open\\command", true);  // open key
404               AnsiString szCmdLine = registry->ReadString("");                                    // read
405               registry->CloseKey();                                                               // close key
406
407               // compose message text and ask user
408               AnsiString szMsgText = "Project file extension '" + szTmp + "' already registered to '" + szOtherApp + "'"
409               + " (" + szCmdLine.SubString(1, szCmdLine.LastDelimiter(" ")-1) + ").\n" + "Re-assign extension to me ??"
410               + "  If you choose 'Cancel' you'll be prompted again next time.";
411               int res = Application->MessageBox(szMsgText.c_str(), "Project file extension alread registered !!"
412                                       , MB_YESNOCANCEL | MB_ICONQUESTION);
413               if(res!=ID_YES)
414                  return res;                         // user canceled
415            }
416         }
417
418         // c) write extensions string (assigning class 'Source2HTML' to extension '.lsc')
419         registry->OpenKey(szTmp, true);                                                        // open key
420         registry->WriteString("", SZ_REGISTRY_KEY);                                            //
421         registry->CloseKey();                                                                  // close key
422
423         // d) write shell command (assigning executable to class 'Source2HTML')
424         registry->OpenKey(AnsiString("\\") + SZ_REGISTRY_KEY + "\\shell\\open\\command", true);// open key
425         registry->WriteString("", Application->ExeName + " %1");                               // set command line
426         registry->CloseKey();                                                                  // close key
427
428         // e) set default icon that is displayed in explorer together with '.lsc' files
429         registry->OpenKey(AnsiString("\\") + SZ_REGISTRY_KEY + "\\DefaultIcon", true);         // open key
430         registry->WriteString("", szDir + SZ_ICON_FILE);                                       // file's icon
431         registry->CloseKey();                                                                  // close key
432
433         return ID_YES;                                                                         // all ok
434      }
435      catch(ERegistryException& err)
436      {
437         Application->MessageBox("Project file extension was not registered!!  You may need administrator\nrights to\
438   access root key 'HKEY_CLASSES_ROOT'!!", "Error accessing registry !!", MB_OK | MB_ICONWARNING);
439         return -1;
440      }
441   }
442
443
444   //----------------------------------------------------------------------------------------------------------------------
445   // response to size changes: re-write file selection list view
446   // Response to 'F1'_ open help using MnOpenHelpClick()
447   void __fastcall TFMain::CmOpenHelp(TWMKey &Msg, bool &Handled)
448   {
449      if(Msg.CharCode==VK_F1)
450         MnOpenHelpClick(this);
451   }
452
453
454   //----------------------------------------------------------------------------------------------------------------------
455   // Show about dialog     note: dialog deletes itself when closed
456   void __fastcall TFMain::MnAboutClick(TObject*)
457   {
458      TFAbout* about = new TFAbout(this, szCmplPrgName, szDir); // create dialog
459      about->ShowModal();                                       // show dialog (modal)
460   }
461
462
463   //----------------------------------------------------------------------------------------------------------------------
464   // open help file
465   void __fastcall TFMain::MnOpenHelpClick(TObject*)
466   {
467      Application->HelpCommand(HELP_CONTENTS, 0);
468   }
469
470
471   //----------------------------------------------------------------------------------------------------------------------
472   // Disallow changing of tab sheet if program is converting
473   void __fastcall TFMain::PageControlChanging(TObject*, bool &AllowChange)
474   {
475      AllowChange = !f_Converting;
476   }
477
478
479   //----------------------------------------------------------------------------------------------------------------------
480   // Enable controls and set focus if the active tab sheets changes
481   void __fastcall TFMain::PageControlChange(TObject*)
482   {
483      // a) Move language drop down list to correct position
484      PositionLanguageDropDownList();
485
486      // b) move language drop down list to the selected tab sheet
487      GbLanguage->Parent = PageControl->ActivePage;
488   }
489
490   //----------------------------------------------------------------------------------------------------------------------
491   void __fastcall TFMain::PageControlResize(TObject *Sender)
492   {
493      // adjust file selection list view
494      RefreshFileSelectionListView();
495
496      // move language drop down list to correct position
497      PositionLanguageDropDownList();
498   }
499
500
501   //----------------------------------------------------------------------------------------------------------------------
502   // Move language drop down list to correct position
503   void TFMain::PositionLanguageDropDownList()
504   {
505      // a) if it's the "Highlighting" tab sheet ...
506      if(PageControl->ActivePage == TsHighlighting)
507      {
508         // position language drop down list
509         GbLanguage->Top = GbCurrentStyle->Top + GbCurrentStyle->Height + 10;
510         GbLanguage->Left = GbStyleSpeedSettings->Left + GbStyleSpeedSettings->Width + 10;
511         GbLanguage->Visible = true;  // show it
512      }
513
514      // b) if it's the "Options" tab sheet ...
515      if(PageControl->ActivePage == TsOptions)
516         GbLanguage->Visible = false;  // hide it
517
518      // c) if it's the "Convert" tab sheet ...
519      if(PageControl->ActivePage == TsConvert)
520      {
521         BtAddFile->SetFocus();     // ... focus on "Add File" button
522         EnableConvertCtrls();      // enable/disable controls
523
524         // position language drop down list
525         GbLanguage->Top = GbFileSelection->Top + GbFileSelection->Height + 2;
526         GbLanguage->Left = 5;
527         GbLanguage->Visible = true;  // show it
528      }
529   }
530
531
532      //-------------------------------------------------------------------------------------------------------------------
533      //   Project management
534      //
535
536   //----------------------------------------------------------------------------------------------------------------------
537   // initialize controls on tab sheet 'Options'
538   void TFMain::EnableOptionsCtrls()
539   {
540      // enable/disable dependant controls in groupbox 'Misc'
541      CbAddLineAnchors->Enabled = project.f_AddLineNumbers;
542
543      // enable/disable dependant controls in groupbox 'Back Links'
544      RbBackLink1->Enabled = project.f_AddBackLink;
545      RbBackLink2->Enabled = project.f_AddBackLink;
546      BtBackLink->Enabled = project.f_AddBackLink && project.f_UserDefinedBackLink;
547      LaBackLinkText->Enabled = project.f_AddBackLink && project.f_UserDefinedBackLink;
548
549      // enable/disable dependant controls in groupbox 'Expert Settings'
550      UdEndlNo->Enabled = project.f_TagClosingOnEndl;
551      LaEndlNo->Enabled = project.f_TagClosingOnEndl;
552      LaHint->Visible = project.f_AddLineNumbers && project.f_TagClosingOnEndl && project.nEndl!=1;
553
554      // enable/disable dependant controls in groupbox 'Overview File'
555      BtSetOverviewFileName->Enabled = project.f_GenerateOverviewFile;
556      LaOverviewFileName->Enabled = project.f_GenerateOverviewFile;
557   }
558
559
560   //----------------------------------------------------------------------------------------------------------------------
561   // set GUI according to project settings   note: Calls OptionsToGUI()
562   void TFMain::ProjectToGUI()
563   {
564      f_ManipCtrls = true;
565
566      //-------------------------------------------------------------------------------------------------------------------
567      // tab sheet 'Options'
568
569
570      //-------------------------------------------------------------------------------------------------------------------
571      // tab sheet 'Convert'
572
573      // group box 'File Selection'
574      CbShowPath->Checked = project.f_ShowPath;
575      CbOverwriteExistingFiles->Checked = project.f_OverwriteExistingFiles;
576      CbEnforceOutputDir->Checked = project.f_EnforceOutputDir;
577      LaOutputDir->Caption = project.szOutputDir;
578
579      // source and destination filenames
580      while(project.nFiles()-LvFiles->Items->Count)      // if there are more filenames in project than in list view
581         (LvFiles->Items->Add())->SubItems->Add("");     // add item and subitem to list view
582
583      RefreshFileSelectionListView();
584
585
586      //-------------------------------------------------------------------------------------------------------------------
587      // tab sheet 'Highlighting'
588      // set style
589      bool f_StyleNotFound = false;
590      if(project.szStyle[0]!='\0')                       // if style name is not empty
591      {
592         int id = styles.GetStyleId(project.szStyle);    // try to find style in list
593         if(id>=0)
594         {                                               // if found ...
595            LbStyles->ItemIndex = id;                       // set style id ...
596            CmStyleChange(this);                            // ... and change style
597         }
598         else
599         {
600            // display warning message if style wasn't found
601            Application->MessageBox((AnsiString("Style '") + project.szStyle + "' not found!  Using defaults!").c_str()
602                        , "Error loading project file !!", MB_OK | MB_ICONWARNING);
603
604            strcpy(project.szStyle, style->szName);   // ... else set style name in project
605            f_StyleNotFound = true;
606         }
607      }
608
609
610      //-------------------------------------------------------------------------------------------------------------------
611      // enable/disable controls
612      OptionsToGUI();
613      EnableOptionsCtrls();
614      EnableConvertCtrls();
615
616      ProjectSaved(!f_StyleNotFound);     // save buttons   Note: function is only called if project is loaded or new empty
617                                          //                      one has been created.
618
619      f_ManipCtrls = false;
620   }
621
622
623   //----------------------------------------------------------------------------------------------------------------------
624   // set GUI according to options settings (TOptions part of TProject)
625   void TFMain::OptionsToGUI()
626   {
627      //-------------------------------------------------------------------------------------------------------------------
628      // tab sheet 'Options'
629
630
631      // groupbox 'Expert Settings'
632      CbTabClosingOnEndl->Checked = project.f_TagClosingOnEndl;
633      CbTags->Checked = project.f_HtmlAndBodyTags;
634      LaEndlNo->Caption = AnsiString(project.nEndl);
635      UdEndlNo->Position = project.nEndl;
636
637
638      // section 'Misc': tab stop positions, indent and language
639      LaTab   ->Caption = AnsiString(project.tabPos);
640      LaIndent->Caption = AnsiString(project.indent);
641      UdIndent->Position = project.indent;
642      UdTab   ->Position = project.tabPos;
643      CbAddBackLink->Checked = project.f_AddBackLink;
644      CbAddTopLinks->Checked = project.f_AddTopLinks;
645      CbAddLineNumbers->Checked = project.f_AddLineNumbers;
646      CbAddLineAnchors->Checked = project.f_AddLineAnchors;
647
648      if(!project.f_UserDefinedBackLink)
649         RbBackLink1->Checked=true;
650      else
651         RbBackLink2->Checked=true;
652      LaBackLinkText->Caption = project.szBackLinkText;
653
654
655      // groupbox 'Generated Overview File'
656      CbGenerateOverviewFile ->Checked = project.f_GenerateOverviewFile;
657      LaOverviewFileName->Caption = MinimizeName(project.szOverviewFileName, LaOverviewFileName->Canvas, LaOverviewFileName->Width*0.9);
658
659
660
661      //-------------------------------------------------------------------------------------------------------------------
662      // enable/disable controls and language
663      EnableOptionsCtrls();
664
665      // language and corresponding sample texts
666      int id = langs.GetId(project.szLanguage);    // try to find langauge
667      if(id<0)                                     // if language wasn't found ...
668      {
669         // ... display warning message
670         AddMessage((AnsiString("Language '") + project.szLanguage + "' not found!  Using defaults!").c_str());
671         if(id<0)                                                 // if still no match is found ...
672            id=0;                                                 // ... use first language as default
673
674        ProjectSaved(false);                       // project is not saved anymore
675      }
676      lang = langs.Get(id);                        // get pointer to language
677      CbLanguage->ItemIndex = id;                  // select language in drop down list
678   }
679
680
681   //----------------------------------------------------------------------------------------------------------------------
682   void TFMain::ProjectSaved(const bool& _f_Saved)
683   {
684      f_Saved = _f_Saved;
685      TbSaveProject->Enabled = !f_Saved;
686      MnSaveProject->Enabled = !f_Saved;
687   }
688
689
690   //----------------------------------------------------------------------------------------------------------------------
691   // response to menu item 'New Project'
692   void __fastcall TFMain::MnNewProjectClick(TObject*)
693   {
694      // a) ask user if project is unsaved
695      if(!f_Saved && project.nFiles()>0)
696         if(Application->MessageBox("Current project settings are not saved! Continue ??", "Question", MB_YESNO | MB_ICONQUESTION)==ID_NO)
697            return;
698
699
700      // a) clear
701      szProjectFile = "";                    // clear project filename
702      Caption = AnsiString(szCmplPrgName);   // reset window caption
703      project.RestoreDefaults(defaults);     // restore defaults for current project's options
704      CmClearList(this);                     // clear file lists (in list view, the ones in project arfe already cleared)
705
706      // b)
707      ProjectToGUI();                        // transfer changes to GUI
708
709      // c) enable/disable controls
710      EnableOptionsCtrls();
711      EnableConvertCtrls();
712   }
713
714   //----------------------------------------------------------------------------------------------------------------------
715   // save project as ...
716   void __fastcall TFMain::MnSaveProjectAsClick(TObject*)
717   {
718      szProjectFile = "";                       // clear project filename
719      Caption = AnsiString(szCmplPrgName);      // reset window caption
720      TbSaveProjectClick(this);                 // save project
721   }
722
723
724   //----------------------------------------------------------------------------------------------------------------------
725   // Save project
726   void __fastcall TFMain::TbSaveProjectClick(TObject*)
727   {
728      // a) ask for filename if project filename is empty
729      if(szProjectFile.IsEmpty())
730      {
731         // set dialog captions and options
732         SaveDialog->Title = "Save project as ...";
733         SaveDialog->Options << ofPathMustExist << ofOverwritePrompt << ofNoReadOnlyReturn;
734         SaveDialog->Filter = "Project file (*." + AnsiString(PROJECT_EXTENSION) + ")|*."
735                              + AnsiString(PROJECT_EXTENSION);
736         SaveDialog->DefaultExt = PROJECT_EXTENSION;        // set default extension
737
738         SaveDialog->FileName = "";                         // clear as ini
739         if(!szProjectFile.IsEmpty())                       // if not empty ...
740            SaveDialog->FileName = szProjectFile;           // ... initialize filename
741         else
742            if(!szProjectDir.IsEmpty())                     // else, again if not empty, ...
743               SaveDialog->InitialDir = szProjectDir;       // ... set directory last time used with 'Save Project' dialog
744
745
746         // execute open dialog and return if dialog closed with cancel
747         if(!SaveDialog->Execute())
748            return;
749
750         // store project filename and directory and display in windows caption
751         szProjectFile = SaveDialog->FileName;
752         szProjectDir  = ExtractFileDir(szProjectFile);
753         Caption = AnsiString(szCmplPrgName) + "     " + szProjectFile;
754      }
755
756
757      // b) save project
758      try
759      {
760         // try to open file and check success
761         ofstream file(szProjectFile.c_str(), ios::out);
762         if(!file)
763            throw TErrText("Unable to open project file: ", szProjectFile.c_str());
764
765         project.Save(file);   // save project
766
767         // display warning if style is temporary, i.e. style name in project is empty
768         if(project.szStyle[0]=='\0')
769            Application->MessageBox("Temporary style wasn't saved. Please save style first.", "Problem saving project file"
770                              , MB_OK | MB_ICONWARNING);
771
772         ProjectSaved(true);  // disable save buttons
773      }
774      catch(TErrText err)
775      {
776         // display error message
777         Application->MessageBox(err.szErrText, "Error saving project file!!", MB_OK | MB_ICONERROR);
778      }
779   }
780
781
782   //----------------------------------------------------------------------------------------------------------------------
783   // ask user for project filename and it using OpenProject()
784   void __fastcall TFMain::TbOpenProjectClick(TObject*)
785   {
786      // a) ask user if project is unsaved
787      if(!f_Saved && project.nFiles()>0)
788         if(Application->MessageBox("Current project settings are not saved! Continue ??", "Question", MB_YESNO | MB_ICONQUESTION)==ID_NO)
789            return;
790
791      f_Saved = true;            // hack to prevent user questioning in MnNewProjectClick()
792      MnNewProjectClick(this);   // clear project
793
794
795      // set dialog captions and options
796      OpenDialog->Title = "Choose Project File ...";
797      OpenDialog->Options << ofFileMustExist << ofPathMustExist;
798      OpenDialog->Filter = "Project file (*." + AnsiString(PROJECT_EXTENSION) + ")|*."
799                           + AnsiString(PROJECT_EXTENSION);
800      OpenDialog->FileName = "";                         // clear as ini
801      if(!szProjectFile.IsEmpty())                       // if not empty ...
802         OpenDialog->FileName = szProjectFile;           // ... initialize filename
803      else
804         if(!szProjectDir.IsEmpty())                     // else, again if not empty, ...
805            OpenDialog->InitialDir = szProjectDir;       // ... set directory last time used with 'Open Project' dialog
806
807
808
809      // execute open dialog and return if dialog closed with cancel
810      if(!OpenDialog->Execute())
811         return;
812
813      // open project
814      OpenProject(OpenDialog->FileName.c_str());
815   }
816
817
818   //----------------------------------------------------------------------------------------------------------------------
819   // open project
820   void TFMain::OpenProject(const char*const& szFileName)
821   {
822      // load project file with exception handling
823      try
824      {
825         // open file for output and check success
826         ifstream file(szFileName, ios::in);
827         if(!file)
828            throw TErrText("Unable to open project file: ", szFileName);
829
830         project.Load(file);
831
832         szProjectFile = szFileName;                                       // store project filename ...
833         szProjectDir  = ExtractFileDir(szProjectFile);                    // ... and directory
834         Caption = AnsiString(szCmplPrgName) + "     " + szProjectFile;    // display project filename in window caption
835         ProjectToGUI();                                                   // transfer changes to GUI
836         PageControl->ActivePage = TsConvert;                              // set active tab sheet
837      }
838      catch(TErrText err)
839      {
840         Application->MessageBox(err.szErrText, "Error loading project file!", MB_OK | MB_ICONERROR);
841         MnNewProjectClick(this);         // clear project again
842      }
843   }
844
845
846   //----------------------------------------------------------------------------------------------------------------------
847   // user has selected a new langauge
848   void __fastcall TFMain::CbLanguageChange(TObject *Sender)
849   {
850      lang = langs.Get(CbLanguage->ItemIndex);     // get pointer to language
851      ProjectSaved(false);                         // project is not saved anymore
852      strcpy(project.szLanguage, lang->Name());    // set new language in project
853   }
854
855
856      //-------------------------------------------------------------------------------------------------------------------
857      //   (default) options management like restore default etc.
858      //
859
860   //----------------------------------------------------------------------------------------------------------------------
861   // set settings to factory defaults
862   void __fastcall TFMain::BtRestoreFactoryDefaultsClick(TObject*)
863   {
864      defaults.RestoreFactoryDefaults();  // restore factory defaults for default options ...
865
866      // ... and copy them to current project's options
867      // note: call base class version as only the options part and not the project part should be set to defaults
868      project.TOptions::RestoreDefaults(defaults);
869
870      OptionsToGUI();                     // transfer changes to GUI
871      SaveDefaults();                     // save defaults
872
873      ProjectSaved(false);                // enable save buttons
874   }
875
876
877   //----------------------------------------------------------------------------------------------------------------------
878   // initialize settings with defaults from ini file
879   void __fastcall TFMain::BtRestoreDefaultsClick(TObject*)
880   {
881      // restore defaults for current project's options
882      // note: call base class version as only the options part and not the project part should be set to defaults
883      project.TOptions::RestoreDefaults(defaults);
884
885      OptionsToGUI();                                    // transfer changes to GUI
886      ProjectSaved(false);                               // enable save buttons
887   }
888
889
890   //----------------------------------------------------------------------------------------------------------------------
891   // save current settings as defaults to ini file
892   void __fastcall TFMain::BtSaveDefaultsClick(TObject*)
893   {
894      defaults.RestoreDefaults(project);  // copy current settings to default settings ...
895      SaveDefaults();                     // ... and save them
896   }
897
898
899   //----------------------------------------------------------------------------------------------------------------------
900   // Utility: Save default settings
901   void TFMain::SaveDefaults()
902   {
903      // save default settings
904      try
905      {
906         // try to open ini file and check success
907         ofstream file((szDir + INI_FILENAME).c_str(), ios::out);
908         if(!file)
909            throw TErrText("Unable to open ini file: ", (szDir + INI_FILENAME).c_str());
910
911         defaults.Save(file);
912      }
913      catch(TErrText err)
914      {
915         Application->MessageBox(err.szErrText, "Error creating ini file! ", MB_OK | MB_ICONWARNING);
916      }
917   }
918
919
920
921
922      //-------------------------------------------------------------------------------------------------------------------
923      //   Response to controls on tab sheet 'Options'
924      //
925
926   //----------------------------------------------------------------------------------------------------------------------
927   // response to check box 'Generate Overview File'
928   void __fastcall TFMain::CbGenerateOverviewFileClick(TObject*)
929   {
930      project.f_GenerateOverviewFile = CbGenerateOverviewFile->Checked;
931      EnableOptionsCtrls();
932      ProjectSaved(false);                                       // enable save buttons
933   }
934
935
936   //----------------------------------------------------------------------------------------------------------------------
937   // Respond to changes of the tab stop positions
938   void __fastcall TFMain::CmTab(TObject*, TUDBtnType Button)
939   {
940      project.tabPos = UdTab->Position;                          // copy new value ...
941      LaTab->Caption = AnsiString(project.tabPos);               // ... and display it
942      ProjectSaved(false);                                       // enable save buttons
943   }
944
945   //----------------------------------------------------------------------------------------------------------------------
946   // Respond to changes of the indent
947   void __fastcall TFMain::CmIndent(TObject*, TUDBtnType Button)
948   {
949      project.indent = UdIndent->Position;                       // copy new value ...
950      LaIndent->Caption = AnsiString(project.indent);            // ... and display it
951      ProjectSaved(false);                                       // enable save buttons
952   }
953
954   //----------------------------------------------------------------------------------------------------------------------
955   // Respond to changes of the "nEndl" setting
956   void __fastcall TFMain::CmEndlNo(TObject*, TUDBtnType Button)
957   {
958      project.nEndl = UdEndlNo->Position;                        // copy new value ...
959      LaEndlNo->Caption = AnsiString(project.nEndl);             // ... and display it
960      EnableOptionsCtrls();                                      // enable/disable hint
961      ProjectSaved(false);                                       // enable save buttons
962   }
963
964   //----------------------------------------------------------------------------------------------------------------------
965   // Respond to changes of the expert mode enable/disable check box
966   void __fastcall TFMain::CmTabClosingOnEndl(TObject*)
967   {
968      project.f_TagClosingOnEndl = CbTabClosingOnEndl->Checked;  // set in project
969
970      // enable/disable the text/updown-control and hint
971      EnableOptionsCtrls();
972
973      // enable save buttons
974      ProjectSaved(false);
975   }
976
977   //----------------------------------------------------------------------------------------------------------------------
978   // Repond to changes of the remaining options chek boxes
979   void __fastcall TFMain::CmTags               (TObject*){ project.f_HtmlAndBodyTags = CbTags->Checked; ProjectSaved(false);}
980   void __fastcall TFMain::CbAddBackLinkClick   (TObject*){ project.f_AddBackLink = CbAddBackLink->Checked; EnableOptionsCtrls(); ProjectSaved(false);}
981   void __fastcall TFMain::CbAddTopLinksClick   (TObject*){ project.f_AddTopLinks = CbAddTopLinks->Checked; ProjectSaved(false);}
982   void __fastcall TFMain::CbAddLineNumbersClick(TObject*){ project.f_AddLineNumbers = CbAddLineNumbers->Checked; EnableOptionsCtrls(); ProjectSaved(false);}
983   void __fastcall TFMain::RbBackLink1Click(TObject*){ project.f_UserDefinedBackLink = RbBackLink2->Checked; EnableOptionsCtrls(); ProjectSaved(false);}
984   void __fastcall TFMain::RbBackLink2Click(TObject *Sender){ project.f_UserDefinedBackLink = RbBackLink2->Checked; EnableOptionsCtrls(); ProjectSaved(false);}
985   void __fastcall TFMain::CbAddLineAnchorsClick(TObject *Sender){ project.f_AddLineAnchors = CbAddLineAnchors->Checked; ProjectSaved(false);}
986
987      //-------------------------------------------------------------------------------------------------------------------
988      //   Functions to show current style in GUI (e.g. preview)
989      //
990
991   //----------------------------------------------------------------------------------------------------------------------
992   // Utility function: Open choose color dialog and write back the result
993   void TFMain::SetColor(char*const& szColor)
994   {
995      // a) convert color string to TColor
996      TColor color = StringToTColor(szColor);
997
998      // b)
999      ColorDialog->Color = color;      // set actual color as default for the color-dialog
1000      ColorDialog->Execute();          // execute the dialog
1001
1002     // c) write back the results
1003     unsigned char* c = (unsigned char*) &(ColorDialog->Color);
1004     sprintf(szColor, "#%02x%02x%02x", (unsigned int) c[0], (unsigned int) c[1], (unsigned int) c[2]);
1005
1006     // d) update preview sample text fields
1007     StyleToPreview();
1008  }
1009
1010
1011  //----------------------------------------------------------------------------------------------------------------------
1012  // set checkboxes according to current style
1013  void TFMain::StyleToCheckboxes()
1014  {
1015     // a) set check boxes for bold styles
1016     CbBold1->Checked = style->f_Bold[TItemStyle::Comment];
1017     CbBold2->Checked = style->f_Bold[TItemStyle::Keyword];
1018     CbBold4->Checked = style->f_Bold[TItemStyle::Symbol];
1019     CbBold5->Checked = style->f_Bold[TItemStyle::String];
1020     CbBold6->Checked = style->f_Bold[TItemStyle::Number];
1021     CbBold7->Checked = style->f_Bold[TItemStyle::Character];
1022     CbBold8->Checked = style->f_Bold[TItemStyle::Preproc];
1023     CbBold9->Checked = style->f_Bold[TItemStyle::Custom1];
1024     CbBoldA->Checked = style->f_Bold[TItemStyle::Custom2];
1025     CbBoldB->Checked = style->f_Bold[TItemStyle::Custom3];
1026     CbBoldC->Checked = style->f_Bold[TItemStyle::Custom4];
1027
1028     // b) set check boxes for italic styles
1029     CbItalic1->Checked = style->f_Italic[TItemStyle::Comment];
1030     CbItalic2->Checked = style->f_Italic[TItemStyle::Keyword];
1031     CbItalic4->Checked = style->f_Italic[TItemStyle::Symbol];
1032     CbItalic5->Checked = style->f_Italic[TItemStyle::String];
1033     CbItalic6->Checked = style->f_Italic[TItemStyle::Number];
1034     CbItalic7->Checked = style->f_Italic[TItemStyle::Character];
1035     CbItalic8->Checked = style->f_Italic[TItemStyle::Preproc];
1036     CbItalic9->Checked = style->f_Italic[TItemStyle::Custom1];
1037     CbItalicA->Checked = style->f_Italic[TItemStyle::Custom2];
1038     CbItalicB->Checked = style->f_Italic[TItemStyle::Custom3];
1039     CbItalicC->Checked = style->f_Italic[TItemStyle::Custom4];
1040  }
1041
1042
1043  //----------------------------------------------------------------------------------------------------------------------
1044  // Utility function for StyleToPreview(): Sets bold and italic style of a TLabel
1045  void SetStyle(TLabel* label, const bool f_Bold, const bool f_Italic)
1046  {
1047     TFontStyles font = label->Font->Style;
1048
1049     if(f_Bold)   font << fsBold;
1050     else         font >> fsBold;
1051
1052     if(f_Italic) font << fsItalic;
1053     else         font >> fsItalic;
1054
1055     label->Font->Style = font;
1056  }
1057
1058
1059  //----------------------------------------------------------------------------------------------------------------------
1060  // Actualize preview sample text fields according to currently active style
1061  void TFMain::StyleToPreview()
1062  {
1063     // a) set sample text font color
1064     LaSample1->Font->Color = StringToTColor(style->szColor[TItemStyle::Comment]);
1065     LaSample2->Font->Color = StringToTColor(style->szColor[TItemStyle::Keyword]);
1066     LaSample3->Font->Color = StringToTColor(style->szColor[TItemStyle::Identifier]);
1067     LaSample4->Font->Color = StringToTColor(style->szColor[TItemStyle::Symbol]);
1068     LaSample5->Font->Color = StringToTColor(style->szColor[TItemStyle::String]);
1069     LaSample6->Font->Color = StringToTColor(style->szColor[TItemStyle::Number]);
1070     LaSample7->Font->Color = StringToTColor(style->szColor[TItemStyle::Character]);
1071     LaSample8->Font->Color = StringToTColor(style->szColor[TItemStyle::Preproc]);
1072     LaSample9->Font->Color = StringToTColor(style->szColor[TItemStyle::Custom1]);
1073     LaSampleA->Font->Color = StringToTColor(style->szColor[TItemStyle::Custom2]);
1074     LaSampleB->Font->Color = StringToTColor(style->szColor[TItemStyle::Custom3]);
1075     LaSampleC->Font->Color = StringToTColor(style->szColor[TItemStyle::Custom4]);
1076
1077
1078     // b) set sample text (and panel) background color
1079     LaSample1->Color = StringToTColor(style->szColor[TItemStyle::Bkgnd]);
1080     LaSample2->Color = StringToTColor(style->szColor[TItemStyle::Bkgnd]);
1081     LaSample3->Color = StringToTColor(style->szColor[TItemStyle::Bkgnd]);
1082     LaSample4->Color = StringToTColor(style->szColor[TItemStyle::Bkgnd]);
1083     LaSample5->Color = StringToTColor(style->szColor[TItemStyle::Bkgnd]);
1084     LaSample6->Color = StringToTColor(style->szColor[TItemStyle::Bkgnd]);
1085     LaSample7->Color = StringToTColor(style->szColor[TItemStyle::Bkgnd]);
1086     LaSample8->Color = StringToTColor(style->szColor[TItemStyle::Bkgnd]);
1087     LaSample9->Color = StringToTColor(style->szColor[TItemStyle::Bkgnd]);
1088     LaSampleA->Color = StringToTColor(style->szColor[TItemStyle::Bkgnd]);
1089     LaSampleB->Color = StringToTColor(style->szColor[TItemStyle::Bkgnd]);
1090     LaSampleC->Color = StringToTColor(style->szColor[TItemStyle::Bkgnd]);
1091     PaPreview->Color = StringToTColor(style->szColor[TItemStyle::Bkgnd]);
1092
1093     // c) set sample text bold and/or italic styles
1094     SetStyle(LaSample1, style->f_Bold[TItemStyle::Comment], style->f_Italic[TItemStyle::Comment]);
1095     SetStyle(LaSample2, style->f_Bold[TItemStyle::Keyword], style->f_Italic[TItemStyle::Keyword]);
1096     SetStyle(LaSample3, style->f_Bold[TItemStyle::Identifier], style->f_Italic[TItemStyle::Identifier]);
1097     SetStyle(LaSample4, style->f_Bold[TItemStyle::Symbol], style->f_Italic[TItemStyle::Symbol]);
1098     SetStyle(LaSample5, style->f_Bold[TItemStyle::String], style->f_Italic[TItemStyle::String]);
1099     SetStyle(LaSample6, style->f_Bold[TItemStyle::Number], style->f_Italic[TItemStyle::Number]);
1100     SetStyle(LaSample7, style->f_Bold[TItemStyle::Character], style->f_Italic[TItemStyle::Character]);
1101     SetStyle(LaSample8, style->f_Bold[TItemStyle::Preproc], style->f_Italic[TItemStyle::Preproc]);
1102     SetStyle(LaSample9, style->f_Bold[TItemStyle::Custom1], style->f_Italic[TItemStyle::Custom1]);
1103     SetStyle(LaSampleA, style->f_Bold[TItemStyle::Custom2], style->f_Italic[TItemStyle::Custom2]);
1104     SetStyle(LaSampleB, style->f_Bold[TItemStyle::Custom3], style->f_Italic[TItemStyle::Custom3]);
1105     SetStyle(LaSampleC, style->f_Bold[TItemStyle::Custom4], style->f_Italic[TItemStyle::Custom4]);
1106
1107     // d)
1108     BtDeleteStyle->Hint = "Delete current style '" + (AnsiString) style->szName +"'";
1109  }
1110
1111
1112  //----------------------------------------------------------------------------------------------------------------------
1113  // Respond to clicks of the "Choose Color" buttons
1114  void __fastcall TFMain::BtColor0Click(TObject*) { SetColor(style->szColor[TItemStyle::Bkgnd]); }
1115  void __fastcall TFMain::BtColor1Click(TObject*) { SetColor(style->szColor[TItemStyle::Comment]); }
1116  void __fastcall TFMain::BtColor2Click(TObject*) { SetColor(style->szColor[TItemStyle::Keyword]); }
1117  void __fastcall TFMain::BtColor3Click(TObject*) { SetColor(style->szColor[TItemStyle::Identifier]); }
1118  void __fastcall TFMain::BtColor4Click(TObject*) { SetColor(style->szColor[TItemStyle::Symbol]); }
1119  void __fastcall TFMain::BtColor5Click(TObject*) { SetColor(style->szColor[TItemStyle::String]); }
1120  void __fastcall TFMain::BtColor6Click(TObject*) { SetColor(style->szColor[TItemStyle::Number]); }
1121  void __fastcall TFMain::BtColor7Click(TObject*) { SetColor(style->szColor[TItemStyle::Character]); }
1122  void __fastcall TFMain::BtColor8Click(TObject*) { SetColor(style->szColor[TItemStyle::Preproc]); }
1123  void __fastcall TFMain::BtColor9Click(TObject*) { SetColor(style->szColor[TItemStyle::Custom1]); }
1124  void __fastcall TFMain::BtColorAClick(TObject*) { SetColor(style->szColor[TItemStyle::Custom2]); }
1125  void __fastcall TFMain::BtColorBClick(TObject*) { SetColor(style->szColor[TItemStyle::Custom3]); }
1126  void __fastcall TFMain::BtColorCClick(TObject*) { SetColor(style->szColor[TItemStyle::Custom4]); }
1127
1128
1129  //----------------------------------------------------------------------------------------------------------------------
1130  // Respond to clicks of the "Bold" check boxes
1131  void __fastcall TFMain::CbBold1Click(TObject*) { style->f_Bold[TItemStyle::Comment] = (CbBold1->Checked);  StyleToPreview(); }
1132  void __fastcall TFMain::CbBold2Click(TObject*) { style->f_Bold[TItemStyle::Keyword] = (CbBold2->Checked);  StyleToPreview(); }
1133  void __fastcall TFMain::CbBold4Click(TObject*) { style->f_Bold[TItemStyle::Symbol] = (CbBold4->Checked);  StyleToPreview(); }
1134  void __fastcall TFMain::CbBold5Click(TObject*) { style->f_Bold[TItemStyle::String] = (CbBold5->Checked);  StyleToPreview(); }
1135  void __fastcall TFMain::CbBold6Click(TObject*) { style->f_Bold[TItemStyle::Number] = (CbBold6->Checked);  StyleToPreview(); }
1136  void __fastcall TFMain::CbBold7Click(TObject*) { style->f_Bold[TItemStyle::Character] = (CbBold7->Checked);  StyleToPreview(); }
1137  void __fastcall TFMain::CbBold8Click(TObject*) { style->f_Bold[TItemStyle::Preproc] = (CbBold8->Checked);  StyleToPreview(); }
1138  void __fastcall TFMain::CbBold9Click(TObject*) { style->f_Bold[TItemStyle::Custom1] = (CbBold9->Checked);  StyleToPreview(); }
1139  void __fastcall TFMain::CbBoldAClick(TObject*) { style->f_Bold[TItemStyle::Custom2] = (CbBoldA->Checked);  StyleToPreview(); }
1140  void __fastcall TFMain::CbBoldBClick(TObject*) { style->f_Bold[TItemStyle::Custom3] = (CbBoldB->Checked);  StyleToPreview(); }
1141  void __fastcall TFMain::CbBoldCClick(TObject*) { style->f_Bold[TItemStyle::Custom4] = (CbBoldC->Checked);  StyleToPreview(); }
1142
1143
1144  //----------------------------------------------------------------------------------------------------------------------
1145  // Respond to clicks of the  "Italic" check boxes
1146  void __fastcall TFMain::CbItalic1Click(TObject*) { style->f_Italic[TItemStyle::Comment] = (CbItalic1->Checked);  StyleToPreview(); }
1147  void __fastcall TFMain::CbItalic2Click(TObject*) { style->f_Italic[TItemStyle::Keyword] = (CbItalic2->Checked);  StyleToPreview(); }
1148  void __fastcall TFMain::CbItalic4Click(TObject*) { style->f_Italic[TItemStyle::Symbol] = (CbItalic4->Checked);  StyleToPreview(); }
1149  void __fastcall TFMain::CbItalic5Click(TObject*) { style->f_Italic[TItemStyle::String] = (CbItalic5->Checked);  StyleToPreview(); }
1150  void __fastcall TFMain::CbItalic6Click(TObject*) { style->f_Italic[TItemStyle::Number] = (CbItalic6->Checked);  StyleToPreview(); }
1151  void __fastcall TFMain::CbItalic7Click(TObject*) { style->f_Italic[TItemStyle::Character] = (CbItalic7->Checked);  StyleToPreview(); }
1152  void __fastcall TFMain::CbItalic8Click(TObject*) { style->f_Italic[TItemStyle::Preproc] = (CbItalic8->Checked);  StyleToPreview(); }
1153  void __fastcall TFMain::CbItalic9Click(TObject*) { style->f_Italic[TItemStyle::Custom1] = (CbItalic9->Checked);  StyleToPreview(); }
1154  void __fastcall TFMain::CbItalicAClick(TObject*) { style->f_Italic[TItemStyle::Custom2] = (CbItalicA->Checked);  StyleToPreview(); }
1155  void __fastcall TFMain::CbItalicBClick(TObject*) { style->f_Italic[TItemStyle::Custom3] = (CbItalicB->Checked);  StyleToPreview(); }
1156  void __fastcall TFMain::CbItalicCClick(TObject*) { style->f_Italic[TItemStyle::Custom4] = (CbItalicC->Checked);  StyleToPreview(); }
1157
1158
1159
1160     //-------------------------------------------------------------------------------------------------------------------
1161     //   Functions for style management like load, save, delete, insert ...
1162     //
1163
1164  //----------------------------------------------------------------------------------------------------------------------
1165  // Insert new style in style list, ask user for its name and select it as active style
1166  // Note: Style file is saved on exit, not here
1167  void __fastcall TFMain::CmSaveStyle(TObject*)
1168  {
1169     //-------------------------------------------------------------------------------------------------------------------
1170     // 1. ask the user for the style's name
1171     AnsiString szTmpName = SZ_DEF_STYLE_NAME;
1172     if(!InputQuery("Insert Style", "Enter a name for the new style:", szTmpName))  // ask and return if user cancels
1173        return;
1174
1175     // return with warning message if entered string is empty
1176     if(szTmpName.IsEmpty())
1177     {
1178        Application->MessageBox("The style name must not be empty!", "Style saving aborted !!", MB_OK | MB_ICONWARNING);
1179        return;
1180     }
1181
1182
1183     //-------------------------------------------------------------------------------------------------------------------
1184     // 2. insert new style in style list
1185     style = &styles.InsertStyle(style);      // insert new style (copied from actual one) and set it as active one
1186
1187
1188
1189     //-------------------------------------------------------------------------------------------------------------------
1190     // 3. exchange '=', ':', '\n', '\t' and '_' from the style's name. All except the last are regarded to be
1191     //    delimiters in the style file and thus they're exchanged. the '_' is exchanged cause a space is encoded
1192     //    with it when the file is written to disk.
1193     strcpy(style->szName, szTmpName.c_str());               // copy name
1194     int i=0;
1195     bool f_Modified = false;
1196     while(style->szName[i]!='\0')
1197     {
1198        if(style->szName[i]==':' || style->szName[i]=='=' || style->szName[i]=='_'
1199              || style->szName[i]=='\n' || style->szName[i]=='\t' )                   // exchange with space
1200        {
1201           style->szName[i]=' ';
1202           f_Modified=true;                                                           // set flag: name was modified
1203        }
1204
1205        i++;
1206     }
1207
1208     // make a message if name was modified
1209     if(f_Modified)
1210        Application->MessageBox("The whitespaces and the characters '=', '_' and ':' were mapped to space!"
1211                                , "Style name was modified !!", MB_OK | MB_ICONINFORMATION);
1212
1213     strcpy(project.szStyle, style->szName);              // set style name in project
1214     ProjectSaved(false);                                 // enable save buttons
1215
1216
1217
1218
1219     //-------------------------------------------------------------------------------------------------------------------
1220     // 4. insert style name in list box, select it and actualize preview
1221     LbStyles->Items->Insert(0, style->szName);
1222     LbStyles->ItemIndex=0;
1223
1224     StyleToPreview();
1225  }
1226
1227
1228  //----------------------------------------------------------------------------------------------------------------------
1229  // User has selected a style from the list box. Set it as active style.
1230  void __fastcall TFMain::CmStyleChange(TObject*)
1231  {
1232     // set the selected style as current one and actualize sample texts and controls
1233     style = styles.GetStyle(LbStyles->ItemIndex);
1234
1235     StyleToPreview();                               // update preview sample text fields
1236     StyleToCheckboxes();                            // set checkboxes according to current style
1237
1238     strcpy(project.szStyle, style->szName);         // set style name in project
1239     ProjectSaved(false);                            // enable save buttons
1240  }
1241
1242
1243  //----------------------------------------------------------------------------------------------------------------------
1244  // Set active style. Take first style, if there are style objects in the style list. Otherwise create new tmporary
1245  // style object.
1246  void TFMain::InitializeStyle()
1247  {
1248     // a) style list is empty: insert new style in style list
1249     if(styles.nStyles()==0)
1250     {
1251        style = &styles.InsertStyle();
1252        strcpy(style->szName, SZ_DEF_STYLE_NAME);             // set its name    (remove?)
1253        project.szStyle[0]='\0';                              // set empty style name in project
1254        LbStyles->Items->Insert(0, SZ_DEF_STYLE_NAME);        // insert item in list box
1255     }
1256
1257     // b) there are style objects in the style list: select the first one
1258     else
1259        style = styles.GetStyle(0);                           // get the first style from the list
1260
1261
1262     strcpy(project.szStyle, style->szName);                  // set style name in project
1263
1264     LbStyles->ItemIndex = 0;
1265     StyleToCheckboxes();       // set checkboxes according to current style
1266     StyleToPreview();          // update preview sample text fields
1267  }
1268
1269
1270  //----------------------------------------------------------------------------------------------------------------------
1271  // Button 'Delete Style' pressed: Delete current style
1272  void __fastcall TFMain::CmDeleteStyle(TObject*)
1273  {
1274     // ask user, if he really wants to delete the currently selected style
1275     char szText[256];
1276     sprintf(szText, "Delete style '%s'??", styles.GetStyle(LbStyles->ItemIndex)->szName);
1277     if(Application->MessageBox(szText, "Style Editing", MB_YESNO | MB_ICONQUESTION) == IDNO)
1278        return;
1279
1280
1281     styles.DeleteStyle(LbStyles->ItemIndex);           // delete from style list
1282     LbStyles->Items->Delete(LbStyles->ItemIndex);      // delete from list box
1283     InitializeStyle();                                 // get another style
1284     SaveStyles();                                      // save using the wrapper
1285
1286     strcpy(project.szStyle, style->szName);            // set new style name in project
1287     ProjectSaved(false);                               // enable save buttons
1288
1289  }
1290
1291
1292  //----------------------------------------------------------------------------------------------------------------------
1293  // Utility: Save styles to file. Display error message if saving fails.
1294  void TFMain::SaveStyles()
1295  {
1296     try
1297     {
1298        // if flag is set: ask if style list shall be saved or not
1299        if(f_StyleLoadError)
1300           if(Application->MessageBox(SZ_SAVE_WARNING, "Warning !!", MB_YESNO | MB_ICONWARNING | MB_DEFBUTTON2)==IDNO)
1301              return;
1302
1303        // save style list moving active style to first
1304        styles.Save((szDir + STYLE_FILENAME).c_str(), LbStyles->ItemIndex);
1305     }
1306     catch(TErrText err)
1307     {
1308        MessageBox(Handle, err.szErrText, "Error saving style file !!", MB_OK | MB_ICONWARNING);
1309     }
1310  }
1311
1312
1313
1314     //-------------------------------------------------------------------------------------------------------------------
1315     //    Functions to manage overview file generation and to open it in browser
1316     //
1317
1318
1319  //----------------------------------------------------------------------------------------------------------------------
1320  // generate overview filename and store it in wrapper.szFileName
1321  void TFMain::IniOverviewFileName()
1322  {
1323     // generate filename using directory of first file in file list as base directory
1324     AnsiString szBaseFile = project.GetDestinationFileName(0);
1325     AnsiString szBaseDir  = IncludeTrailingBackslash(ExtractFileDir(szBaseFile));
1326
1327     // store filename of overview file
1328     strcpy(wrapper.szFileName, (szBaseDir + project.szOverviewFileName).c_str());
1329  }
1330
1331
1332  //----------------------------------------------------------------------------------------------------------------------
1333  // return relative filename
1334  const char* TFMain::MakeRelativeLink(const char*const& szBaseFile, const char*const& szFileName)
1335  {
1336     // a) write link considering relative paths
1337     char szTmpPath[STS];
1338     strcpy(szTmpPath, Sysutils::ExtractRelativePath(szBaseFile, szFileName).c_str());
1339
1340     // b) exchange backslash by '/'
1341     int i = 0;
1342     while(szTmpPath[i]!='\0')
1343     {
1344        if(szTmpPath[i]=='\\')
1345           szTmpPath[i]='/';
1346        i++;
1347     }
1348
1349
1350     // c) prepend protocol 'file://' if link contains drive
1351     static char szRelPath[STS];
1352     if(!ExtractFileDir(szTmpPath).IsEmpty())
1353        sprintf(szRelPath, "file://%s", szTmpPath);
1354     else
1355        strcpy(szRelPath, szTmpPath);
1356
1357
1358     // c) return
1359     return szRelPath;
1360  }
1361
1362
1363  //----------------------------------------------------------------------------------------------------------------------
1364  // Generate overview file
1365  void TFMain::GenerateOverviewFile()
1366  {
1367     //-------------------------------------------------------------------------------------------------------------------
1368     // 1. pre-play
1369
1370
1371
1372     // if not disabled: check if overview file alread exists
1373     if(!project.f_OverwriteExistingFiles)
1374     {
1375        ifstream file(wrapper.szFileName, ios::in);                                   // try to open for reading(!)
1376        if(file)
1377           if(Application->MessageBox(wrapper.szFileName,                             // ask user if file already exists
1378           "File already exists!  Overwrite it ??", MB_YESNO | MB_ICONWARNING)==IDNO)
1379              return;
1380     }
1381
1382     // GUI update
1383     AddMessage("Generated overview file " + (AnsiString) wrapper.szFileName);
1384     BtViewInBrowser->Enabled = true;   // enable button
1385
1386
1387     // open file
1388     ofstream file(wrapper.szFileName, ios::out);
1389
1390
1391     //-------------------------------------------------------------------------------------------------------------------
1392     // 2. write header
1393     file << "<html>" << endl << "<head>" << endl;
1394     file << "   <title>Overview: Files</title>" << endl;
1395     file << "   <meta name=\"generator\" content=\"" << SZ_HTML_PRGNAME << " - http://" << SZ_HTML_PRGLINK << "\">" << endl;
1396     file << "</head>" << endl << endl;
1397     file << "<body text=\"#000000\" bgcolor=\"#ffffff\" vlink=\"#660066\" alink=\"#3300cc\" link=\"#3300cc\">";
1398     file << endl << endl << "<basefont face=\"Arial\">" << endl << endl;
1399     file << "<h1>Overview</h1>" << endl << endl;
1400     if(project.f_UserDefinedBackLink)
1401        file << "<p><font color=\"#FF0000\">User defined back link text. Back link may be broken.</font></p>" << endl << endl;
1402     file << "<table cellpadding=\"3\">" << endl;
1403
1404
1405     //-------------------------------------------------------------------------------------------------------------------
1406     // 3. write table with names/links for each file in filelist
1407     for(int i=0;i<project.nFiles();i++)
1408     {
1409        // a) write link considering relative paths   -  Note: backslash is exchanged by '/'
1410        file << "<tr><td><a href=\"" << MakeRelativeLink(wrapper.szFileName, project.GetDestinationFileName(i)) << "\">";
1411
1412
1413        // b) write filename
1414        file << "<font size=\"+1\" face=\"arial\"> " << (Sysutils::ExtractFileName(project.GetSourceFileName(i))).c_str();
1415        file << " </font></a>" << "</td></tr>" << endl;
1416     }
1417     file << "</table>" << endl << endl;
1418
1419
1420     //-------------------------------------------------------------------------------------------------------------------
1421     // 4. write statistics and link to program's homepage
1422     file << "<p>Converted by <a href=\"http://www.newty.de/lsc/index.html\" target=_parent>";
1423     file << "<i>" << SZ_HTML_PRGNAME << "</i></a>";
1424
1425
1426     file << "<br>Converted a total of " << (toDo/1024) << "kb in ";
1427     file << (endTime-startTime)/CLK_TCK << " seconds</p>" << endl << endl;
1428
1429
1430     file << "</body></html>";
1431  }
1432
1433
1434  //----------------------------------------------------------------------------------------------------------------------
1435  // Function executes the shell command in an additional thread - see below
1436  void ViewHtmlFile(void* _tmp)
1437  {
1438     TFMain::THandleWrap* tmp = (TFMain::THandleWrap*) _tmp;
1439     ShellExecute(tmp->hwnd, "open", tmp->szFileName, 0, 0, SW_NORMAL);
1440  }
1441
1442
1443  //----------------------------------------------------------------------------------------------------------------------
1444  // Function to open the last converted file in the browser. Called via a thread function which executes
1445  // the necessary shell command. Done this way cause some browsers need a long time to open ... ;-)
1446  void __fastcall TFMain::CmViewInBrowser(TObject*)
1447  {
1448     // check if the file still exists and if not ...
1449     ifstream test(wrapper.szFileName);
1450     if(!test)
1451     {
1452        // ... disable button
1453        BtViewInBrowser->Enabled = false;
1454
1455        // inform user
1456        MessageBox(Handle, wrapper.szFileName, "Ups, the file seems to be history ...", MB_OK | MB_ICONWARNING);
1457     }
1458     else
1459        _beginthread(ViewHtmlFile, 4096, (void*) &wrapper);     // else: everythings ok -> start browser
1460  }
1461
1462
1463
1464
1465     //-------------------------------------------------------------------------------------------------------
1466     //    Functions for management of the source and target filename lists/list view
1467     //
1468
1469  //----------------------------------------------------------------------------------------------------------------------
1470  // Respond to drag&drop message. Query dropped files and add them to the lists/list view.
1471  void __fastcall TFMain::EvDragDrop(TMessage& msg)
1472  {
1473     // get number of dropped files
1474     int n = DragQueryFile((HANDLE) msg.WParam, 0xFFFFFFFF, NULL, 0);
1475     if(n==0)
1476        return;
1477
1478
1479     // succesively query filenames and add them to project file lists using AddName2Lists()
1480     for(int i=0;i<n;i++)
1481     {
1482        char szFileName[MAXPATH];
1483        DragQueryFile((HANDLE) msg.WParam, i, szFileName, sizeof(szFileName));   // query filename
1484
1485        // if extension of first filename matches project file extension
1486        if(i==0)
1487        {
1488           if(ExtractFileExt(szFileName) == AnsiString(".") + PROJECT_EXTENSION)
1489           {
1490              MnNewProjectClick(this);      // clear project
1491              OpenProject(szFileName);      // ... open project
1492              return;                       // ... and return
1493           }
1494        }
1495        // else ...
1496        AddName2Lists(szFileName);          // add filename to file lists and list view
1497     }
1498
1499     RefreshFileSelectionListView();        // refresh list view
1500     PageControl->ActivePage = TsConvert;   // change tab to 'Convert'
1501     ProjectSaved(false);                   // enable save buttons
1502  }
1503
1504
1505  //----------------------------------------------------------------------------------------------------------------------
1506  // Open dialog and let the user add a file to the file list
1507  void __fastcall TFMain::CmAddFile(TObject*)
1508  {
1509     // a) select language specific file filter
1510     OpenDialog->Filter = AnsiString(lang->Name()) + " (" + lang->Extensions() + ")|" + lang->Extensions() +
1511                           "|Any file (*.*)|*.*";
1512
1513
1514     // b) set dialog captions and options
1515     OpenDialog->Title = "Choose Source File(s) ...";
1516     OpenDialog->Options << ofFileMustExist << ofPathMustExist << ofAllowMultiSelect;
1517     OpenDialog->FileName = "";                      // clear as ini
1518     if(!szSourceDir.IsEmpty())                      // if not empty ...
1519        OpenDialog->InitialDir = szSourceDir;        // ... set directory last time used with 'AddFile' dialog
1520
1521
1522     // c) execute open dialog and return if dialog closed with cancel
1523     if(!OpenDialog->Execute()) return;
1524
1525
1526     // d) add name(s) to file lists and list view
1527     for(int i=0;i<OpenDialog->Files->Count;i++)
1528        AddName2Lists(OpenDialog->Files->Strings[i]);
1529
1530     // e) refresh list view and save buttons
1531     RefreshFileSelectionListView();
1532     ProjectSaved(false);
1533     szSourceDir = ExtractFileDir(OpenDialog->Files->Strings[0]);  // save source directory
1534  }
1535
1536
1537  //----------------------------------------------------------------------------------------------------------------------
1538  // Utility function: Adds message to the list box and ensures visibility
1539  void TFMain::AddMessage(const AnsiString& szMessage)
1540  {
1541     if(LbMessages->Items->Count > MAX_MESSAGES_IN_LISTVIEW)        // eventually delete oldest message
1542        LbMessages->Items->Delete(0);
1543
1544     LbMessages->Items->Add(szMessage);
1545     LbMessages->TopIndex = LbMessages->Items->Count-1;             // ensure visibility of the new message
1546  }
1547
1548
1549  //----------------------------------------------------------------------------------------------------------------------
1550  // refresh file selection list view
1551  void TFMain::RefreshFileSelectionListView()
1552  {
1553     // for all items
1554     for(int i=0;i<LvFiles->Items->Count;i++)     // note: check box states are queried in ModifyFileName()
1555     {
1556        LvFiles->Items->Item[i]->Caption              = ModifyFileName(project.GetSourceFileName(i));            // source
1557        LvFiles->Items->Item[i]->SubItems->Strings[0] = ModifyFileName(project.GetDestinationFileName(i), true); // target
1558     }
1559  }
1560
1561
1562  //----------------------------------------------------------------------------------------------------------------------
1563  // If it's not already in the lists: Add filename to project filelist
1564  void TFMain::AddName2Lists(const AnsiString& szName)
1565  {
1566     // a) check for dupes
1567     for(int i=0;i<project.nFiles();i++)
1568        if(strcmp(project.GetSourceFileName(i), szName.c_str())==0)
1569        {
1570           AddMessage("File already in list! Refused to add: " + szName);
1571           return;
1572        }
1573
1574
1575     // b) add source and destination filename to project
1576     project.AddFileNames(szName.c_str(), (szName + ".html").c_str());
1577
1578
1579     // c) add item and subitem to list view
1580     (LvFiles->Items->Add())->SubItems->Add("");
1581
1582
1583     // d) enable buttons
1584     EnableConvertCtrls();
1585  }
1586
1587
1588  //----------------------------------------------------------------------------------------------------------------------
1589  // Utility function: Return filename with or without path
1590  // Note: filename is already with exchanged path (f_EnforceOutputDir==true)
1591  AnsiString TFMain::ModifyFileName(AnsiString szFileName, const bool& f_Destination/*=false*/)
1592  {
1593     if(CbShowPath->Checked)
1594        return MinimizeName(szFileName, LvFiles->Canvas, LvFiles->Columns->Items[0]->Width*0.9);
1595     else
1596     {
1597        int endPath = szFileName.LastDelimiter("\\");
1598        return szFileName.SubString(endPath+1, szFileName.Length()-endPath);
1599     }
1600  }
1601
1602
1603  //----------------------------------------------------------------------------------------------------------------------
1604  void __fastcall TFMain::LvFilesResize(TObject*)
1605  {
1606     LvFiles->Columns->Items[0]->Width = LvFiles->ClientWidth/2;
1607     LvFiles->Columns->Items[1]->Width = LvFiles->ClientWidth/2;
1608  }
1609
1610
1611  //----------------------------------------------------------------------------------------------------------------------
1612  // Redirect insert and delete keys
1613  void __fastcall TFMain::LvOnKeyDown(TObject*, WORD &Key, TShiftState Shift)
1614  {
1615     if(Key==VK_DELETE) CmDelete(this);
1616     if(Key==VK_INSERT) CmAddFile(this);
1617  }
1618
1619
1620  //----------------------------------------------------------------------------------------------------------------------
1621  // User clicked check box "Show Path". Update list view
1622  void __fastcall TFMain::CmPath(TObject*)
1623  {
1624     if(f_ManipCtrls)              // return if executed due to state change by program
1625        return;
1626
1627     project.f_ShowPath = CbShowPath->Checked;    // set new state in project
1628     RefreshFileSelectionListView();              // refresh list view
1629     ProjectSaved(false);                         // enable save buttons
1630  }
1631
1632
1633  //----------------------------------------------------------------------------------------------------------------------
1634  //
1635  void __fastcall TFMain::CbEnforceOutputDirClick(TObject*)
1636  {
1637     if(f_ManipCtrls)              // return if executed due to state change by program
1638        return;
1639
1640     project.f_EnforceOutputDir = CbEnforceOutputDir->Checked;   // set in project
1641     EnableConvertCtrls();                                       // enable/disable controls
1642     RefreshFileSelectionListView();                             // refresh list view
1643     ProjectSaved(false);                                        // enable save buttons
1644  }
1645
1646
1647  //----------------------------------------------------------------------------------------------------------------------
1648  // open directory selection dialog
1649  void __fastcall TFMain::BtSetOutputDirClick(TObject*)
1650  {
1651     // a) initialize default directory where dialog starts
1652     AnsiString szDir;                      // directory
1653     if(project.szOutputDir[0]!='\0')       // if not empty ...
1654        szDir = project.szOutputDir;        // ... initialize directory from project
1655     else
1656        if(!szOutputDir.IsEmpty())          // else, again if not empty, ...
1657           szDir = szOutputDir;             // ... set directory last time used with select directory dialog
1658
1659     // b) set dialog's options
1660     TSelectDirOpts opt;
1661     opt << sdAllowCreate << sdPerformCreate << sdPrompt;
1662
1663
1664     // c) execute select directory dialog
1665     if(SelectDirectory(szDir, opt, 0))
1666     {
1667        // if closed with OK button
1668
1669        // display chosen directory an set it in project
1670        LaOutputDir->Caption = MinimizeName(IncludeTrailingBackslash(szDir), LaOutputDir->Canvas, LaOutputDir->Width);
1671        strcpy(project.szOutputDir, IncludeTrailingBackslash(szDir).c_str());
1672
1673        // refresh list view and enable save buttons
1674        RefreshFileSelectionListView();
1675        ProjectSaved(false);
1676        szOutputDir = szDir;
1677     }
1678  }
1679
1680
1681  //----------------------------------------------------------------------------------------------------------------------
1682  // User clicked check box "Overwrite existing files"
1683  void __fastcall TFMain::CbOverwriteExistingFilesClick(TObject*)
1684  {
1685     if(f_ManipCtrls)              // return if executed due to state change by program
1686        return;
1687
1688     project.f_OverwriteExistingFiles = CbOverwriteExistingFiles->Checked;   // set new state in project
1689     ProjectSaved(false);                                                    // enable save buttons
1690  }
1691
1692
1693  //----------------------------------------------------------------------------------------------------------------------
1694  // User clicked in list view: enable/disable "Delete"/"Rename" buttons
1695  void __fastcall TFMain::CmListView(TObject*)
1696  {
1697     EnableConvertCtrls();
1698  }
1699
1700
1701  //----------------------------------------------------------------------------------------------------------------------
1702  // Remove selected file from lists/list view
1703  void __fastcall TFMain::CmDelete(TObject*)
1704  {
1705     // a) get selected file and it's index, return if none is selected
1706     TListItem* item = LvFiles->Selected;
1707
1708     if(!item)
1709        return;
1710
1711     const int index = LvFiles->Items->IndexOf(item);
1712
1713
1714     // b) delete from filelists/list view
1715     project.DeleteFileName(index);
1716     LvFiles->Items->Delete(index);
1717
1718
1719     // if there are still list elements
1720     LvFiles->Selected = LvFiles->Items->Item[min(index, LvFiles->Items->Count-1)];
1721     ActiveControl = LvFiles;   // set focus back
1722
1723
1724     // c) enable/disable controls and enable save buttons
1725     EnableConvertCtrls();
1726     ProjectSaved(false);
1727  }
1728
1729
1730  //----------------------------------------------------------------------------------------------------------------------
1731  // Rename selected (target-)filename
1732  void __fastcall TFMain::CmRename(TObject*)
1733  {
1734     // a) disable buttons
1735     EnableConvertCtrls();
1736
1737
1738     // b) get selected file and it's index, return if none is selected
1739     TListItem* item = LvFiles->Selected;
1740
1741     if(!item)
1742        return;
1743
1744     const int index = LvFiles->Items->IndexOf(item);
1745
1746
1747     // c) set dialogs captions and options
1748     SaveDialog->Title       = "Enter Target Filename ...";
1749     SaveDialog->Filter      = "HTML files (*.html;*.htm)|*.html;*.htm|Any file (*.*)|*.*";
1750     SaveDialog->DefaultExt  = "html";             // default extension - added if none specified
1751
1752     SaveDialog->Options << ofNoReadOnlyReturn;
1753     SaveDialog->FileName = project.GetDestinationFileName(index);
1754
1755
1756     // d) execute dialog and return if dialog closed with cancel
1757     if(!SaveDialog->Execute())
1758        return;
1759
1760
1761     // e) check for dupes
1762     for(int i=0;i<project.nFiles();i++)
1763        if(strcmp(project.GetDestinationFileName(i), SaveDialog->FileName.c_str())==0)
1764        {
1765           MessageBox(Handle, SaveDialog->FileName.c_str(), "Target filename already in list! Refused to rename!"
1766                                            , MB_ICONWARNING | MB_OK);
1767           return;
1768        }
1769
1770
1771     // f) write back modified target filename and enable save buttons
1772     project.SetDestinationFileName(SaveDialog->FileName.c_str(), index);       // file list
1773     item->SubItems->Strings[0] = ModifyFileName(SaveDialog->FileName, true);   // list view
1774     ProjectSaved(false);
1775  }
1776
1777
1778  //----------------------------------------------------------------------------------------------------------------------
1779  void __fastcall TFMain::DisableDeleteAndRename(TObject*)
1780  {
1781     // disable buttons
1782     BtDelete->Enabled = false;
1783     BtRename->Enabled = false;
1784  }
1785
1786
1787  //----------------------------------------------------------------------------------------------------------------------
1788  // Clear file lists/list view
1789  void __fastcall TFMain::CmClearList(TObject*)
1790  {
1791     project.ClearFileNames();              // clear file lists
1792     LvFiles->Items->Clear();               // clear list view
1793
1794     EnableConvertCtrls();                  // enable/disable controls
1795     ProjectSaved(false);                   // enable save buttons
1796  }
1797
1798
1799  //----------------------------------------------------------------------------------------------------------------------
1800  // enable/disable controls on tab sheet convert
1801  void TFMain::EnableConvertCtrls()
1802  {
1803     // buttons
1804     BtDelete->Enabled = (LvFiles->Selected) && (ActiveControl==LvFiles);
1805     BtRename->Enabled = (LvFiles->Selected) && (ActiveControl==LvFiles);
1806     BtClear->Enabled  = (project.nFiles()!=0);
1807     BtStart->Enabled  = (project.nFiles()!=0);
1808
1809     // output directory controls
1810     BtSetOutputDir->Enabled = CbEnforceOutputDir->Checked;
1811     LaOutputDir->Enabled = CbEnforceOutputDir->Checked;
1812  }
1813
1814
1815
1816     //-------------------------------------------------------------------------------------------------------
1817     //    Functions to start/do the converting process
1818     //
1819
1820  //----------------------------------------------------------------------------------------------------------------------
1821  // Start converting using additional thread
1822  void __fastcall TFMain::CmStart(TObject*)
1823  {
1824     // a) disable buttons and drag&drop
1825     GbFileSelection->Enabled = false;
1826     CbLanguage->Enabled = false;
1827     BtClear   ->Enabled = false;
1828     BtDelete  ->Enabled = false;
1829     BtRename  ->Enabled = false;
1830     BtAddFile ->Enabled = false;
1831     CbShowPath->Enabled = false;
1832     DragAcceptFiles(Handle, false);    // disable drag&drop
1833
1834
1835     // b) if not disabled: check if target files already exist
1836     if(!project.f_OverwriteExistingFiles)
1837     {
1838        char* szText = new char[STS+MAXPATH*project.nFiles()];      // this should be enough :-)
1839        szText[0] = '\0';      // terminate
1840
1841        // check each file
1842        for(int i=0;i<project.nFiles();i++)
1843        {
1844           const char* szName = project.GetDestinationFileName(i);
1845
1846           // try to open for reading(!)
1847           ifstream file(szName, ios::in);
1848
1849           if(file)
1850           {
1851              strcat(szText, szName);
1852              strcat(szText, "\n");
1853           }
1854        }
1855
1856        // ask user if some files already exist
1857        if(szText[0]!='\0')
1858           if(Application->MessageBox(szText, "The following file(s) already exist! Overwrite them?",
1859                                   MB_YESNO | MB_ICONWARNING | MB_DEFBUTTON2)==ID_NO)
1860           {
1861              delete[] szText;
1862              Finish(false);    // adjust/reset controls (buttons, timers) again etc.
1863              return;
1864           }
1865
1866        delete[] szText;
1867     }
1868
1869
1870     // c) move message window etc. 80 pixel up to make progress bars visible
1871     BtViewInBrowser->Top -= 80;
1872     BtStart        ->Top -= 80;
1873     BtCancel       ->Top -= 80;
1874     GbMessages     ->Top -= 80;
1875     GbLanguage     ->Top -= 80;
1876     GbFileSelection->Height -= 80;      // resize file selection group box
1877     LvFiles        ->Height += 75;      // after group box size change: correct list view
1878
1879
1880
1881     // d) reset gauges and make progress bars and cancel button visible
1882     ProgressBar1->Position = 0;
1883     ProgressBar2->Position = 0;
1884     GbProgress->Visible = true;
1885     BtStart   ->Visible = false;
1886     BtCancel  ->Visible = true;
1887
1888
1889     // e) set flag, reset progress counter and start timer for display actualization
1890     f_Converting   = true;
1891     f_Stop         = false;
1892     Timer->Enabled = true;
1893
1894     toDo      = 1;                   // to prevent "divison by zero" errors
1895     done      = 0;
1896     startTime = clock();             // get time
1897
1898     IniOverviewFileName();           // initialize filename of overview file
1899
1900
1901     // f) start thread which does all the work in its member-function Execute - note: deletes itself
1902     new ThreadFunc(false, this);
1903  }
1904
1905
1906  //----------------------------------------------------------------------------------------------------------------------
1907  // Actualize progress bars
1908  void __fastcall TFMain::OnTimer(TObject*)
1909  {
1910     // hint: altering screen components is expensive. thus check!
1911     int tmp = progress*inv5Percent;
1912     if(tmp>gaugePos)
1913     {
1914        gaugePos = tmp;
1915        ProgressBar1->Position = tmp * 5;
1916        ProgressBar2->Position = 100 * (progress+done) / toDo;
1917     }
1918  }
1919
1920
1921  //----------------------------------------------------------------------------------------------------------------------
1922  // Function is called when the conversion thread finishes
1923  void TFMain::Finish(const bool& f_AllOk/*=true*/)
1924  {
1925     // conversion progress was not aborted before(!) conversion thread was started
1926     if(f_AllOk)
1927     {
1928        // stop timer
1929        endTime = clock();                  // get time
1930        Timer->Enabled = false;             // stop
1931
1932        // write overview of generated files       note: must be executed before CmClearList() and after ini of endTime (?)
1933        GenerateOverviewFile();
1934
1935        // move message window etc. 80 pixel down again
1936        BtViewInBrowser->Top += 80;
1937        BtStart        ->Top += 80;
1938        BtCancel       ->Top += 80;
1939        GbMessages     ->Top += 80;
1940        GbLanguage     ->Top += 80;
1941        GbFileSelection->Height += 80;      // resize file selection group box
1942        LvFiles        ->Height -= 75;      // after group box size change: move list view
1943
1944
1945        // exchange 'Cancel' and 'Start' button again
1946        BtStart ->Visible = true;
1947        BtCancel->Visible = false;
1948        f_Converting = false;               // reset flag
1949
1950        AddMessage("Finished!");            // add message
1951     }
1952     else
1953        AddMessage("Aborted!");
1954
1955
1956     // enable/disable controls
1957     GbProgress->Visible = false;           // hide groupbox with progress bars
1958     GbFileSelection->Enabled = true;       // enable file selection group box
1959     BtAddFile ->Enabled = true;            // buttons
1960     CbShowPath->Enabled = true;            // check boxes
1961     CbLanguage->Enabled = true;            // language radio buttons
1962     DragAcceptFiles(Handle, true);         // enable drag&drop again
1963
1964     EnableConvertCtrls();
1965
1966     // set focus etc.
1967     BtAddFile->SetFocus();
1968     AddMessage("");                        // add empty line
1969  }
1970
1971
1972  //----------------------------------------------------------------------------------------------------------------------
1973  // User clicks "Cancel" button: set stop flag
1974  void __fastcall TFMain::CmCancel(TObject*) { f_Stop = true; }
1975
1976
1977
1978
1979  //----------------------------------------------------------------------------------------------------------------------
1980  // Response to 'Set Name' button in group box 'Overview File'
1981  void __fastcall TFMain::BtSetOverviewFileNameClick(TObject *Sender)
1982  {
1983     // ask the user for the overview file name
1984     AnsiString szFileName = project.szOverviewFileName;
1985     if(!InputQuery("Overview File", "Enter File Name ...", szFileName))  // ask and return if user cancels
1986        return;
1987
1988     // return with warning message if entered string is empty
1989     if(szFileName.IsEmpty())
1990     {
1991        Application->MessageBox("The file name must not be empty!", "Overview file", MB_OK | MB_ICONWARNING);
1992        return;
1993     }
1994
1995
1996     // display file name
1997     szFileName = ChangeFileExt(szFileName, ".html");            // ensure correct extension
1998     strcpy(project.szOverviewFileName, szFileName.c_str());     // set filename in project
1999     LaOverviewFileName->Caption = project.szOverviewFileName;
2000     ProjectSaved(false);
2001  }
2002
2003
2004  //-------------------------------------------------------------------------------------------------------------------
2005  // Response to 'Set Link Text' button in group box 'Back Links'
2006  void __fastcall TFMain::BtBackLinkClick(TObject *Sender)
2007  {
2008     // 1. ask the user for the back link text
2009     AnsiString szText = project.szBackLinkText;
2010     if(!InputQuery("Back Links", "Enter Text ...", szText))  // ask and return if user cancels
2011        return;
2012
2013     // return with warning message if entered string is empty
2014     if(szText.IsEmpty())
2015     {
2016        Application->MessageBox("The text must not be empty!", "Back Links", MB_OK | MB_ICONWARNING);
2017        return;
2018     }
2019
2020     // display file name
2021     strcpy(project.szBackLinkText, szText.c_str());     // set text in project
2022     LaBackLinkText->Caption = project.szBackLinkText;
2023     ProjectSaved(false);
2024  }

Top