source: trunk/NewView/MainForm.pas@ 489

Last change on this file since 489 was 489, checked in by ataylor, 21 months ago

Support drag-and-drop of Locale objects.

  • Property svn:eol-style set to native
File size: 189.8 KB
Line 
1Unit MainForm;
2
3// NewView - a new OS/2 Help Viewer
4// Copyright 2003-2006 Aaron Lawrence (aaronl at consultant dot com)
5// Copyright 2006-2007 Ronald Brill (rbri at rbri dot de)
6// This software is released under the Gnu Public License - see readme.txt
7
8Interface
9
10Uses
11// system is a good unit to be able to open ;)
12// the above line is here so you can use right-mouse open file on "system"
13 OS2Def,
14 SysUtils,
15 Classes,
16 Forms,
17 Graphics,
18 Messages,
19 Buttons,
20 ComCtrls,
21 StdCtrls,
22 ExtCtrls,
23 TabCtrls,
24 Dialogs,
25
26// library
27 ACLString,
28 ACLStringUtility,
29 SharedMemoryUnit,
30 ACLLanguageUnit,
31 GenericThread,
32 CmdLineParameterUnit,
33
34// custom components
35 SplitBar,
36 Outline2,
37 RichTextView,
38 Coolbar2,
39 CustomListBox,
40
41// local
42 HelpFile,
43 HelpTopic,
44 HelpWindowUnit,
45 HelpWindowDimensions,
46 NavigatePointUnit,
47 MiscUnit,
48 HelpManagerUnit,
49 TextSearchQuery,
50 IPFFileFormatUnit,
51 Tabset2Unit;
52
53const
54 // Custom window messages for this form
55 // NOTE! Sibyl uses WM_USER+1 and +2!
56 WM_OPENED = WM_USER + 10;
57 WM_FOLLOWLINK = WM_USER + 11;
58 WM_FOLLOWEXTERNALLINK = WM_USER + 12;
59
60 MAIN_WINDOW_CLASS_NAME = 'NewViewMainForm';
61
62Type
63
64 TMainForm = Class (TForm)
65 VSplitBar: TSplitBar;
66 Notebook: TNoteBook;
67 IndexSearchEdit: TEdit;
68 SearchTextEdit: TEdit;
69 SearchResultsListBox: TListBox;
70 NotesListBox: TListBox;
71 CoolBar: TCoolBar2;
72 MenuItem21: TMenuItem;
73 SaveAsIPFMI: TMenuItem;
74 MenuItem20: TMenuItem;
75 DebugFindBinaryMI: TMenuItem;
76 TopicByNameMI: TMenuItem;
77 DebugTopicByResourceIDMI: TMenuItem;
78 ToolsDebugSep: TMenuItem;
79 DebugSaveLanguageFileMI: TMenuItem;
80 DebugLoadLanguageMI: TMenuItem;
81 TabSet: TTabSet2;
82 NavigateNextMI: TMenuItem;
83 ShowLeftPanelMI: TMenuItem;
84 MenuItem18: TMenuItem;
85 AddNoteButton: TButton;
86 EditNoteButton: TButton;
87 DeleteNoteButton: TButton;
88 GotoNoteButton: TButton;
89 MenuItem23: TMenuItem;
90 MenuItem24: TMenuItem;
91 MenuItem25: TMenuItem;
92 DebugHelpManagerVersionMI: TMenuItem;
93 MenuItem19: TMenuItem;
94 ViewHighlightSearchWordsMI: TMenuItem;
95 MenuItem17: TMenuItem;
96 MenuItem16: TMenuItem;
97 MenuItem15: TMenuItem;
98 FileNewWindowMI: TMenuItem;
99 OpenSpecialMI: TMenuItem;
100 MenuItem14: TMenuItem;
101 SearchPMI: TMenuItem;
102 ViewSourceMI: TMenuItem;
103 FileCloseMI: TMenuItem;
104 MenuItem10: TMenuItem;
105 MenuItem12: TMenuItem;
106 MenuItem13: TMenuItem;
107 StatusPanel: TPanel;
108 ProgressPanel: TPanel;
109 ProgressBar: TProgressBar;
110 DebugShowWordSeparatorsMI: TMenuItem;
111 DebugStressTestMI: TMenuItem;
112 TopicPropertiesPMI: TMenuItem;
113 MenuItem3: TMenuItem;
114 MenuItem2: TMenuItem;
115 MenuItem8: TMenuItem;
116 ToolsOptionsMI: TMenuItem;
117 MenuItem9: TMenuItem;
118 ToolsDebugMenu: TMenuItem;
119 DebugShowParamsMI: TMenuItem;
120 DebugShowCodesMI: TMenuItem;
121 EditGlobalSearchMI: TMenuItem;
122 ViewExpandAllMI: TMenuItem;
123 EditBookmarksMI: TMenuItem;
124 AddBookmarkMI: TMenuItem;
125 ViewPopupMenu: TPopupMenu;
126 SelectAllPMI: TMenuItem;
127 CopyPMI: TMenuItem;
128 ContentsOutline: TOutline2;
129 IndexListBox: TCustomListBox;
130 ViewCollapseAllMI: TMenuItem;
131 MenuItem7: TMenuItem;
132 SystemOpenDialog: TSystemOpenDialog;
133 SearchButton: TButton;
134 MenuItem1: TMenuItem;
135 ViewIndexMI: TMenuItem;
136 ViewContentsMI: TMenuItem;
137 ViewSearchMI: TMenuItem;
138 ViewNotesMI: TMenuItem;
139 ViewRefreshMI: TMenuItem;
140 MenuItem11: TMenuItem;
141 DisplayPanel: TPanel;
142 ButtonImages: TImageList;
143 BookmarksMenu: TMenuItem;
144 MainMenu: TMainMenu;
145 FileMenu: TMenuItem;
146 OpenMI: TMenuItem;
147 FileSaveAsMI: TMenuItem;
148 PrintMI: TMenuItem;
149 FileInformationMI: TMenuItem;
150 MenuItem4: TMenuItem;
151 ExitMI: TMenuItem;
152 EditMenu: TMenuItem;
153 SelectAllMI: TMenuItem;
154 CopyMI: TMenuItem;
155 MenuItem5: TMenuItem;
156 FindMI: TMenuItem;
157 FindNextMI: TMenuItem;
158 NavigateMenu: TMenuItem;
159 NavigateBackMI: TMenuItem;
160 NavigateForwardMI: TMenuItem;
161 MenuItem6: TMenuItem;
162 NavigatePreviousMI: TMenuItem;
163 ToolsMenu: TMenuItem;
164 GlobalSearchMI: TMenuItem;
165 HelpMenu: TMenuItem;
166 HelpMI: TMenuItem;
167 HelpProductInformationMI: TMenuItem;
168 AddNoteMI: TMenuItem;
169
170 Procedure SaveAsIPFMIOnClick (Sender: TObject);
171 Procedure DebugFindBinaryMIOnClick (Sender: TObject);
172 Procedure TopicByNameMIOnClick (Sender: TObject);
173 Procedure CopyLinkLocationPMIOnClick (Sender: TObject);
174 Procedure HelpKeysMIOnClick (Sender: TObject);
175 Procedure MainFormOnCommand (Sender: TObject; Var Command: TCommand);
176 Procedure MainFormOnScan (Sender: TObject; Var KeyCode: TKeyCode);
177 Procedure ShowLeftPanelMIOnClick (Sender: TObject);
178 Procedure CoolBarOnFontChange (Sender: TObject);
179 Procedure NotebookOnFontChange (Sender: TObject);
180 Procedure TabSetOnFontChange (Sender: TObject);
181 Procedure IndexListBoxOnFontChange (Sender: TObject);
182 Procedure NotesListBoxOnFontChange (Sender: TObject);
183 Procedure DisplayPanelOnFontChange (Sender: TObject);
184 Procedure ContentsOutlineOnFontChange (Sender: TObject);
185 Procedure SearchResultsListBoxOnFontChange (Sender: TObject);
186 Procedure DisplayPanelOnDragOver (Sender: TObject; Source: TObject;
187 X: LongInt; Y: LongInt; State: TDragState; Var Accept: Boolean);
188 Procedure NotesListBoxOnDragOver (Sender: TObject; Source: TObject;
189 X: LongInt; Y: LongInt; State: TDragState; Var Accept: Boolean);
190 Procedure DisplayPanelOnDragDrop (Sender: TObject; Source: TObject;
191 X: LongInt; Y: LongInt);
192 Procedure NotesListBoxOnDragDrop (Sender: TObject; Source: TObject;
193 X: LongInt; Y: LongInt);
194 Procedure SearchResultsListBoxOnDragDrop (Sender: TObject; Source: TObject;
195 X: LongInt; Y: LongInt);
196 Procedure SearchResultsListBoxOnDragOver (Sender: TObject; Source: TObject;
197 X: LongInt; Y: LongInt; State: TDragState; Var Accept: Boolean);
198 Procedure IndexListBoxOnDragDrop (Sender: TObject; Source: TObject;
199 X: LongInt; Y: LongInt);
200 Procedure IndexListBoxOnDragOver (Sender: TObject; Source: TObject;
201 X: LongInt; Y: LongInt; State: TDragState; Var Accept: Boolean);
202 Procedure ContentsOutlineOnDragOver (Sender: TObject; Source: TObject;
203 X: LongInt; Y: LongInt; State: TDragState; Var Accept: Boolean);
204 Procedure ContentsOutlineOnDragDrop (Sender: TObject; Source: TObject;
205 X: LongInt; Y: LongInt);
206 Procedure MainFormOnDragOver (Sender: TObject; Source: TObject; X: LongInt;
207 Y: LongInt; State: TDragState; Var Accept: Boolean);
208 Procedure MainFormOnDragDrop (Sender: TObject; Source: TObject; X: LongInt;
209 Y: LongInt);
210 Procedure ContentsOutlineOnItemClick (Node: TNode);
211 Procedure DebugLoadLanguageMIOnClick (Sender: TObject);
212 Procedure DebugSaveLanguageFileMIOnClick (Sender: TObject);
213 Procedure SearchResultsListBoxOnClick (Sender: TObject);
214 Procedure VSplitBarOnDblClick (Sender: TObject);
215 Procedure DebugHelpManagerVersionMIOnClick (Sender: TObject);
216 Procedure DebugTopicByResourceIDMIOnClick (Sender: TObject);
217 Procedure ViewHighlightSearchWordsMIOnClick (Sender: TObject);
218 Procedure FileNewWindowMIOnClick (Sender: TObject);
219 Procedure OpenSpecialMIOnClick (Sender: TObject);
220 Procedure NotesListBoxOnScan (Sender: TObject; Var KeyCode: TKeyCode);
221 Procedure ViewPopupMenuOnPopup (Sender: TObject);
222 Procedure SearchPMIOnClick (Sender: TObject);
223 Procedure ViewSourceMIOnClick (Sender: TObject);
224 Procedure PrintMIOnClick (Sender: TObject);
225 Procedure DebugShowWordSeparatorsMIOnClick (Sender: TObject);
226 Procedure DebugStressTestMIOnClick (Sender: TObject);
227 Procedure TopicPropertiesPMIOnClick (Sender: TObject);
228 Procedure NavigateForwardMIOnClick (Sender: TObject);
229 Procedure IndexListBoxOnScan (Sender: TObject; Var KeyCode: TKeyCode);
230 Procedure SearchResultsListBoxOnScan (Sender: TObject;
231 Var KeyCode: TKeyCode);
232 Procedure ContentsOutlineOnScan (Sender: TObject; Var KeyCode: TKeyCode);
233 Procedure ToolsOptionsMIOnClick (Sender: TObject);
234 Procedure EditGlobalSearchMIOnClick (Sender: TObject);
235 Procedure DebugShowParamsMIOnClick (Sender: TObject);
236 Procedure ViewExpandAllMIOnClick (Sender: TObject);
237 Procedure EditBookmarksMIOnClick (Sender: TObject);
238 Procedure CopyPMIOnClick (Sender: TObject);
239 Procedure SelectAllPMIOnClick (Sender: TObject);
240 Procedure AddNoteButtonOnClick (Sender: TObject);
241 Procedure SearchTextEditOnChange (Sender: TObject);
242 Procedure IndexListBoxOnClick (Sender: TObject);
243 Procedure ViewCollapseAllMIOnClick (Sender: TObject);
244 Procedure NotesListBoxOnDblClick (Sender: TObject);
245 Procedure HelpMIOnClick (Sender: TObject);
246 Procedure NotebookOnPageChanged (Sender: TObject);
247 Procedure ViewRefreshMIOnClick (Sender: TObject);
248 Procedure ViewNotesMIOnClick (Sender: TObject);
249 Procedure ViewSearchMIOnClick (Sender: TObject);
250 Procedure ViewIndexMIOnClick (Sender: TObject);
251 Procedure ViewContentsMIOnClick (Sender: TObject);
252 Procedure MainFormOnCloseQuery (Sender: TObject; Var CanClose: Boolean);
253 Procedure GlobalSearchMIOnClick (Sender: TObject);
254 Procedure GotoNoteButtonOnClick (Sender: TObject);
255 Procedure EditNoteButtonOnClick (Sender: TObject);
256 Procedure NotesListBoxOnItemFocus (Sender: TObject; Index: LongInt);
257 Procedure DeleteNoteButtonOnClick (Sender: TObject);
258 Procedure AddBookmarkMIOnClick (Sender: TObject);
259 Procedure AddNoteMIOnClick (Sender: TObject);
260 Procedure FileCloseMIOnClick (Sender: TObject);
261 Procedure CoolBarOnSectionResize (HeaderControl: THeaderControl;
262 section: THeaderSection);
263 Procedure CoolBarOnSectionClick (HeaderControl: THeaderControl;
264 section: THeaderSection);
265 Procedure MainFormOnDestroy (Sender: TObject);
266 Procedure MainFormOnSetupShow (Sender: TObject);
267 Procedure MainFormOnCreate (Sender: TObject);
268 Procedure MainFormOnShow (Sender: TObject);
269 Procedure FindNextMIOnClick (Sender: TObject);
270 Procedure FindMIOnClick (Sender: TObject);
271 Procedure IndexSearchEditOnScan (Sender: TObject; Var KeyCode: TKeyCode);
272 Procedure IndexSearchEditOnChange (Sender: TObject);
273 Procedure FileInformationMIOnClick (Sender: TObject);
274 Procedure SearchTextEditOnScan (Sender: TObject; Var KeyCode: TKeyCode);
275 Procedure SearchButtonOnClick (Sender: TObject);
276 Procedure FileSaveAsMIOnClick (Sender: TObject);
277 Procedure OptionsMIOnClick (Sender: TObject);
278 Procedure TabSetOnChange (Sender: TObject; NewTab: LongInt;
279 Var AllowChange: Boolean);
280 Procedure NotebookOnSetupShow (Sender: TObject);
281 Procedure NavigateBackMIOnClick (Sender: TObject);
282 Procedure NavigatePreviousMIOnClick (Sender: TObject);
283 Procedure NavigateNextMIOnClick (Sender: TObject);
284 Procedure CopyMIOnClick (Sender: TObject);
285 Procedure SelectAllMIOnClick (Sender: TObject);
286 Procedure DebugShowCodesMIOnClick (Sender: TObject);
287 Procedure HelpProductInformationMIOnClick (Sender: TObject);
288 Procedure OnOverLink ( Sender: TRichTextView; LinkString: String);
289 Procedure OnNotOverLink ( Sender: TRichTextView; LinkString: String);
290 Procedure OnClickLink ( Sender: TRichTextView; LinkString: String);
291 Procedure BackButtonOnClick (Sender: TObject);
292 Procedure RTViewOnSetupShow (Sender: TObject);
293 Procedure OpenMIOnClick (Sender: TObject);
294 Procedure ExitMIOnClick (Sender: TObject);
295
296 Procedure MainFormOnResize (Sender: TObject);
297 Procedure VSplitBarOnChange (NewSplit: LongInt);
298 Protected
299 // Custom window messages ----------------------------------
300
301 // Handle our own WM_OPENED message
302 Procedure WMOpened( Var Msg: TMessage ); Message WM_OPENED;
303 Procedure WMFollowLink( Var Msg: TMessage ); Message WM_FOLLOWLINK;
304 Procedure WMFollowExternalLink( Var Msg: TMessage ); Message WM_FOLLOWEXTERNALLINK;
305
306 // Messages from new help manager OR other instances
307 Procedure NHMDisplayIndex( Var Msg: TMessage ); Message NHM_HELP_INDEX;
308 Procedure NHMDisplayContents( Var Msg: TMessage ); Message NHM_HELP_CONTENTS;
309 Procedure NHMTopicByResourceID( Var Msg: TMessage ); Message NHM_TOPIC_BY_RESOURCE_ID;
310 Procedure NHMTopicByPanelName( Var Msg: TMessage ); Message NHM_TOPIC_BY_PANEL_NAME;
311
312 Procedure NHMTest( Var Msg: TMessage ); Message NHM_TEST;
313
314 Procedure NHMSearch( Var Msg: TMessage ); Message NHM_SEARCH;
315 Procedure NHMGlobalSearch( Var Msg: TMessage ); Message NHM_GLOBAL_SEARCH;
316 Procedure NHMShowUsage( Var Msg: TMessage ); Message NHM_SHOW_USAGE;
317
318 Procedure NHMSetFiles( Var Msg: TMessage ); Message NHM_SET_FILES;
319 Procedure NHMSetTitle( Var Msg: TMessage ); Message NHM_SET_TITLE;
320
321 Protected
322 // GUI events set by code ----------------------------------
323
324 Procedure OnHint( Sender: TObject );
325 Procedure OnWindowClose( Window: THelpWindow );
326 Procedure OnWindowAboutToClose( Window: THelpWindow;
327 var CanClose: boolean );
328 Procedure OnNavigateToMenuItemClick( Sender: TObject );
329 Procedure OnDragOverWindow( Sender: TObject;
330 Source: TObject;
331 X: LongInt;
332 Y: LongInt;
333 State: TDragState;
334 Var Accept: Boolean );
335 Procedure OnDragDropToWindow( Sender: TObject;
336 Source: TObject;
337 X: LongInt;
338 Y: LongInt );
339 Procedure OnWindowFontChange( Sender: TObject );
340 Procedure OnWindowTab( Sender: TObject );
341 Procedure OnWindowBackTab( Sender: TObject );
342
343 Procedure OnException( Sender: TObject;
344 E: Exception );
345 Procedure OnHelp( context: THelpContext;
346 var Result: Boolean );
347
348
349 FShowLeftPanel: boolean;
350
351 Function GetShowLeftPanel: boolean;
352 Procedure SetShowLeftPanel( Value: boolean );
353 Property ShowLeftPanel: boolean read GetShowLeftPanel write SetShowLeftPanel;
354
355 Procedure ShowTab( TabIndex: longint );
356
357 procedure GetClassData(var ClassData: TClassData); override;
358 Public
359
360 // Open the file or list of files in FileNames
361 // Set the window title if given, otherwise get it from first file
362 Function OpenFiles( const FileNames: TStrings;
363 const WindowTitle: string;
364 const DisplayFirstTopic: boolean ): boolean;
365
366 // Open a single file
367 Function OpenFile( const FileName: string;
368 const WindowTitle: string;
369 const DisplayFirstTopic: boolean ): boolean;
370
371 Function OpenAdditionalFiles( const FileNames: TStrings;
372 const DisplayFirstTopic: boolean ): boolean;
373
374 Function OpenAdditionalFile( const FileName: string;
375 const DisplayFirstTopic: boolean ): boolean;
376
377 // open from original helpmgr style file1+file2+file3. ..
378 Function OpenFilesFromTextList( const TextList: string;
379 const DisplayFirstTopic: boolean ): boolean;
380
381 Procedure CloseFile;
382 Function OKToCloseFile: boolean;
383
384 Procedure AddCurrentToMRUFiles;
385
386 Function LoadFiles( const FileNames: TStrings;
387 HelpFiles: TList ): boolean;
388 Procedure DisplayFiles( NewFiles: TList;
389 Var FirstContentsNode: TNode );
390
391 Procedure OpenDroppedFile( Source: TObject );
392
393 Function OpenWindowsHelp( const Filename: string ): boolean;
394
395 function DisplayTopicByResourceID( ID: uint16 ): boolean;
396 function DisplayTopicByName( const TopicName: string ): boolean;
397 function DisplayTopicByGlobalName( const TopicName: string ): boolean;
398
399 Procedure DisplayIndex;
400 Procedure DisplayContents;
401 Procedure DisplaySearch;
402
403 Protected
404 // Startup functions ----------------------------------
405
406 Function pSharedStruct: TPNewHelpMgrSharedStruct;
407 Procedure PositionWindow;
408 Procedure RestoreWindow;
409
410 Procedure CheckEnvironmentVars;
411 Procedure ShowUsage;
412
413 // Loading functions ----------------------------------
414
415 // Most recently used files list
416 Procedure CreateMRUMenuItems;
417 Procedure OnMRUMenuItemClick( Sender: TObject );
418
419 Procedure OnHelpFileLoadProgress( n, outof: integer;
420 message: string );
421
422 // Returns nil if file is not open
423 Function FindOpenHelpFile( FileName: string ): THelpFile;
424
425 // Navigation -------------------------------------------------
426
427 Procedure SaveNavigatePoint;
428 Procedure SaveWindows( SourceList: TList;
429 DestList: TList;
430 Parent: TSavedHelpWindow );
431
432 Procedure UpdateCurrentNavigatePoint;
433 Procedure ClearPageHistory;
434
435 Procedure NavigateToPoint( NavPoint: TNavigatePoint );
436 Procedure NavigateToHistoryIndex( Index: longint );
437
438 Procedure DisplayWindows( WindowList: TList;
439 Parent: THelpWindow );
440 Procedure ShowWindows;
441 Procedure ShowWindowList( WindowList: TList );
442 Procedure CloseWindows;
443
444 Procedure FocusFirstHelpWindow;
445
446 Procedure NavigateBack;
447 Procedure NavigateForward;
448 Procedure NavigatePreviousInContents;
449 Procedure NavigateNextInContents;
450
451 Procedure CreateNavigateToMenuItems;
452
453 // GUI status updates ---------------------------------
454
455 Procedure EnableControls;
456 Procedure EnableSearchButton;
457 Procedure SetStatus( Text: String );
458 Procedure SetProgress( n, outof: integer;
459 message: string );
460 Procedure ResetProgress;
461 Procedure RefreshWindows( WindowList: TList );
462
463 // language stuff
464 // called by callback
465 Procedure OnLanguageEvent( Language: TLanguageFile;
466 const Apply: boolean );
467
468 function ShowCodes: boolean;
469 function ShowWordIndices: boolean;
470
471 // Loading views --------------------------------------
472
473 // Used in loading contents
474 Procedure AddChildNodes( HelpFile: THelpFile;
475 ParentNode: TNode;
476 Level: longint;
477 Var TopicIndex: longint );
478 Procedure LoadContents( Files: TList;
479 Var FirstNode: TNode );
480 Procedure LoadIndex;
481
482 // Note manipulations --------------------------------
483
484 procedure AddNote;
485 Procedure EditNote( NoteIndex: longint );
486 procedure DeleteNote( NoteIndex: longint );
487 Procedure SaveNotes;
488 Procedure SaveNotesForFile( HelpFile: THelpFile );
489 Procedure LoadNotes( HelpFile: THelpFile );
490 Procedure GotoCurrentNote;
491
492 // make sure that note insert positions are not in
493 // the middle of tags due to help file or newview updates.
494 Procedure CorrectNotesPositions( Topic: TTopic;
495 Text: pchar );
496
497 Procedure InsertNotesIntoTopicText( Topic: TTopic;
498 Text: TAString );
499 function FindOriginalNoteCharIndex( NoteCharIndex: longword;
500 Topic: TTopic ): longword;
501 function FindActualNoteCharIndex( NoteCharIndex: longword;
502 MaxNoteIndex: longword;
503 Topic: TTopic ): longword;
504 procedure RefreshNoteInsertInfo( NoteIndex: longword );
505 procedure ClearNotes;
506
507 Procedure EnableNotesControls;
508 Procedure UpdateNotesDisplay;
509
510 Procedure RefreshFontSubstitutions;
511
512 // GUI actions ------------------------------------------
513
514 procedure FileOpen;
515
516 Procedure PrintTopics;
517 function DoPrinting( Parameters: TObject ): TObject;
518 Procedure StopPrinting;
519
520 Procedure DoFind( FindOrigin: TFindOrigin );
521
522 // Bookmarks ------------------------------------------
523
524 Procedure NavigateToBookmark( Bookmark: TBookmark );
525 Procedure BuildBookmarksMenu;
526 Procedure UpdateBookmarksForm;
527 Procedure BookmarksMenuItemClick( Sender: TObject );
528 procedure AddBookmark;
529 procedure ClearBookmarks;
530 procedure SaveBookmarks;
531 procedure SaveBookmarksForFile( HelpFile: THelpFile );
532 procedure LoadBookmarks( HelpFile: THelpFile );
533 procedure OnBookmarksChanged( Sender: TObject );
534
535 // Global search -------------------------------------
536
537 procedure DoGlobalSearch( const SearchText: string );
538 // Called when viewing topics from global search
539 Procedure OnViewGlobalSearchTopic( FileName: string;
540 TopicIndex: longint );
541
542 // Options and appearance -----------------------------
543
544 procedure DoOptions;
545
546 procedure ApplySettings;
547
548 // changes normal or fixed font depending on shift state
549 Procedure SetTopicFont( NewFont: TFont );
550
551 Procedure SetApplicationFont( NewFont: TFont );
552
553 // Retrieve control colours (in case drag'n'drop used to change)
554 Procedure GetColors;
555 // Set the layout of the main form
556 Procedure SetLayout;
557 // Lay out the specified list of help windows
558 Procedure LayoutWindowList( WindowList: TList );
559 // Setup the rich text views in the specified windows (e.g for changing global settings)
560 Procedure SetupViews( WindowList: TList );
561
562 // Topic display -------------------------------------
563
564 // Major display topic function.
565 procedure DisplayTopic( Topic: TTopic );
566
567 Procedure DisplaySelectedIndexTopic;
568 Procedure DisplaySelectedSearchResultTopic;
569 Procedure DisplaySelectedContentsTopic;
570
571 Procedure DisplayTopicInWindow( Window: THelpWindow;
572 FollowAutoLinks: boolean;
573 KeepPosition: boolean );
574
575 function OpenWindow( Topic: TTopic;
576 Group: longint;
577 Parent: THelpWindow;
578 Rect: THelpWindowRect;
579 FollowAutoLinks: boolean ): THelpWindow;
580
581 Procedure RemoveHelpWindowFromParent( Window: THelpWindow );
582
583 Procedure FollowLink( Link: THelpLink;
584 SourceWindow: THelpWindow );
585
586 Function FindTopicByResourceID( ID: uint16 ): TTopic;
587 Function FindTopicByName( const Name: string ): TTopic;
588 Function FindTopicByGlobalName( const Name: string ): TTopic;
589
590 Function FindTopicForLink( Link: THelpLink ): TTopic;
591
592 Function FindWindowFromView( View: TRichTextView; WindowList: TList ): THelpWindow;
593 Function FindWindowFromGroup( Group: longint; WindowList: TList ): THelpWindow;
594 Function FindWindowFromTopic( Topic: TTopic; WindowList: TList ): THelpWindow;
595 Function GetActiveWindow: THelpWindow;
596
597 Procedure DoSearch;
598 Procedure SearchFor( const SearchText: string );
599 Procedure StartupTopicSearch( const SearchText: string );
600
601 // clear search match sequences
602 Procedure ClearAllWordSequences;
603
604 Procedure SetMainCaption;
605
606 // cancel help manager mode
607 Procedure ClearHelpManager;
608 Procedure PostHelpManagerMessage( MessageType: ULONG;
609 Param1: long;
610 Param2: long );
611
612 HelpManagerWindows: TList; // of HWND
613
614 function OwnHelpMode: boolean;
615 CurrentOpenFiles: TList; // current open help files.
616 MRUMenuItems: TList; // most recently used file list
617 NavigateToMenuItems: TList;
618 MainTitle: string;
619
620 // Current topic has the vague meaning that it was the last
621 // topic selected by the user... (?)
622 CurrentTopic: TTopic;
623
624 AllFilesWordSequences: TList; // of lists; one per open file; of possible word sequences
625
626 // use during decode...
627 TopicText: TAString;
628
629 Windows: TList; // top level help windows
630
631 PageHistory: TStringList; // history
632 CurrentHistoryIndex: longint; // where we are in history
633
634 Navigating: boolean; // true while going to a particular history point
635
636 DisplayedIndex: TStringList; // duplicate of index listbox,
637 // for fast case insensitive searching
638 InIndexSearch: boolean; // true while searching index
639 IndexLoaded: boolean;
640
641 ContentsLoaded: boolean;
642
643 StartingUp: boolean; // true while starting
644 SettingFont: boolean;
645 DisplayingTopicWindow: boolean;
646
647 FindText: string; // last text found (Ctrl-F)
648
649 Notes: TList; // Notes in current files.
650
651 Bookmarks: TList;
652 BookmarksMenuItems: TList;
653
654 // while loading... so owe can display progress
655 LoadingFilenameList: TStringList;
656 LoadingFileIndex: integer;
657
658 PrintThread: TGenericThreadManager;
659 procedure OnPrintProgress( n, outof: integer;
660 Message: string );
661 procedure OnPrintComplete( Dummy: TObject );
662 protected
663 // language stuff
664 FileOpenTitle: string;
665 LoadingFileMsg: string;
666 HelpFileError: string;
667 LoadingStatusDisplaying: string;
668 LoadingStatusNotesAndBookmarks: string;
669 LoadingStatusContents: string;
670 LoadingStatusIndex: string;
671 LoadingStatusDone: string;
672
673 AllFilesDesc: string;
674 HelpFilesDesc: string;
675 LanguageFilesDesc: string;
676
677 SaveLanguageTitle: string;
678 OpenLanguageTitle: string;
679 SaveLanguageError: string;
680
681 HelpManagerVersionTitle: string;
682
683 FindResourceIDTitle: string;
684 FindResourceIDPrompt: string;
685 InvalidResourceIDError: string;
686 ResourceIDNotFoundError: string;
687
688 OpenSpecialTitle: string;
689 OpenSpecialPrompt: string;
690
691 PrintTopicTitle: string;
692 NoPrinterError: string;
693 SelectWindowToPrintError: string;
694 PrintingError: string;
695 StoppingPrintMsg: string;
696 PrintStoppedMsg: string;
697 CheckStopPrintTitle: string;
698 CheckStopPrintMsg: string;
699
700 TopicInfoTitle: string;
701 TopicInfoTopicTitle: string;
702 TopicInfoIndex: string;
703 TopicInfoFile: string;
704 TopicInfoResourceIDs: string;
705 TopicInfoNoResourceIDs: string;
706
707 ParameterCountLabel: string;
708
709 NewViewHelpTitle: string;
710 AlreadyNewviewHelp: string;
711 NewViewHelpNotFound: string;
712
713 InvalidLinkErrorTitle: string;
714 InvalidLinkError: string;
715 InvalidResourceIDLinkErrorA: string;
716 InvalidResourceIDLinkErrorB: string;
717
718 OpenedTopicMsg: string;
719
720 AddNoteTitle: string;
721 AddNoteCursorError: string;
722 NoteWithinNoteError: string;
723 LoadNotesTitle: string;
724 LoadNotesError: string;
725 SaveNotesTitle: string;
726 SaveNotesError: string;
727
728 UntitledBookmarkName: string;
729 LoadBookmarksTitle: string;
730 LoadBookmarksError: string;
731 SaveBookmarksTitle: string;
732 SaveBookmarksError: string;
733
734 ApplicationErrorTitle: string;
735 ApplicationErrorA: string;
736 ApplicationErrorB: string;
737 ApplicationErrorC: string;
738
739 EnvironmentVarErrorTitle: string;
740 EnvironmentVarError: string;
741 EnvironmentVarUndefined: string;
742
743 FindTitle: string;
744 FindSelectWindowError: string;
745 FindPrompt: string;
746 TextNotFoundMsg: string;
747
748 FilesInfoTitle: string;
749 FilesInfoOverallTitle: string;
750 FilesInfoFilename: string;
751 FilesInfoFileTitle: string;
752 FilesInfoTopicCount: string;
753 FilesInfoIndexCount: string;
754 FilesInfoDictionaryCount: string;
755 FilesInfoFileSize: string;
756 FilesInfoTotalTopicCount: string;
757 FilesInfoTotalIndexCount: string;
758 FilesInfoTotalFileSize: string;
759
760 SearchTitle: string;
761 SearchSyntaxError: string;
762 SearchingMsg: string;
763 NoSearchMatchesMsg: string;
764 SearchFoundMsgA: string;
765 SearchFoundMsgB: string;
766
767 FileSaveTitle: string;
768 FileSaveSelectWindowError: string;
769 DefaultSaveTopicFilename: string;
770 ReplaceFilePromptA: string;
771 ReplaceFilePromptB: string;
772 UnableToSaveError: string;
773
774 UsageTitle: string;
775 UsageText1: string;
776 UsageText2: string;
777 UsageText3: string;
778 UsageText4: string;
779 UsageText5: string;
780 UsageText6: string;
781 UsageText7: string;
782 UsageText8: string;
783
784 GoBackHint: string;
785
786 SelectAllTitle: string;
787 SelectAllWindowError: string;
788
789 EditNoteMsg: string;
790 ExternalLinkMsg: string;
791 LinkMsg: string;
792 UnknownLinkMsg: string;
793 FootnoteMsg: string;
794
795 ExternalLinkTitle: string;
796 ExternalLinkError: string;
797
798 MRUMultipleFilesHint: string;
799
800 HelpProgramTitle: string;
801 WindowsHelpTitle: string;
802 WindowsHelpPrompt: string;
803
804 ErrorTitle: string;
805
806 FindTopicNameTitle: string;
807 FindTopicNamePrompt: string;
808 TopicNameNotFoundError: string;
809
810 SplitBarDblClickToShow: string;
811 SplitBarDblClickToHide: string;
812
813 End;
814
815Var
816 MainForm: TMainForm;
817 CmdLineParameters : TCmdLineParameters;
818
819Implementation
820
821uses
822 BseDos,
823 BseErr,
824 PMWin,
825 PmShl,
826 Dos,
827 Printers,
828
829 // Library
830 ACLFileIOUtility,
831 ACLUtility,
832 ACLDialogs,
833 RunProgramUnit,
834 StringUtilsUnit,
835 CharUtilsUnit,
836 DebugUnit,
837
838 FileUtilsUnit,
839
840 // Components
841 RichTextPrintUnit,
842 RichTextStyleUnit,
843 RichTextDocumentUnit,
844 ControlsUtility,
845
846 // local: forms
847 InformationFormUnit,
848 OptionsForm,
849 ProductInformationFormUnit,
850 NoteForm,
851 GlobalSearchForm,
852 FileDialogForm,
853 BookmarksFormUnit,
854 PrintDialogUnit,
855
856 // local: others
857 NewViewConstantsUnit,
858 SettingsUnit,
859 VersionUnit,
860 SearchUnit,
861 StartupUnit,
862 GlobalFilelistUnit,
863 WebBrowserUnit,
864 HelpBitmap;
865
866{$R Images}
867
868const
869 // Coolbar button indexes
870 ciOpen = 0;
871 ciPrint = 1;
872 ciNavigator = 2;
873 ciBack = 3;
874 ciForward = 4;
875 ciAddNote = 5;
876 ciAddBookmark = 6;
877 ciPrevious = 7;
878 ciNext = 8;
879 ciGlobalSearch = 9;
880
881 // Page indexes.
882 piContents = 0;
883 piIndex = 1;
884 piSearch = 2;
885 piNotes = 3;
886
887 CrashLogFileName = 'NewView.log';
888
889 _MAX_PATH = 260;
890
891var
892 hNewViewDLL: HMODULE;
893
894 StartMem: longword;
895 LastMem: longword;
896
897 g_ExternalLinkFilename: string;
898 g_ExternalLinkTopic: string;
899 g_ExternalLinkSourceFilename: string;
900 g_ExternalLinkKeepCurrent: boolean; // whether to keep current files open
901
902 g_LastSysModalWindow: HWND;
903
904//
905// ----------------------------------------------------------------------------------------
906// TMainForm implementation
907// ----------------------------------------------------------------------------------------
908//
909
910Procedure TMainForm.SaveAsIPFMIOnClick (Sender: TObject);
911var
912 FileName: string;
913 F: TextFile;
914 H: THelpFile;
915 i: longint;
916 T: TTopic;
917 ResourceIDs: TList;
918 ImageOffsets: TList;
919 ImageOffset: longint;
920 Image: THelpBitmap;
921Begin
922 H := CurrentOpenFiles[ 0 ];
923
924 FileName := ChangeFileExt( ExtractFileName( H.Filename ), '.ipf' );
925 if not DoSaveFileDialog( FileSaveTitle,
926 'IPF' + '|*.ipf',
927 Filename,
928 Settings.LastSaveDirectory,
929 Filename ) then
930 exit;
931 if FileExists( Filename ) then
932 if not DoConfirmDlg( FileSaveTitle,
933 ReplaceFilePromptA
934 + Filename
935 + ReplaceFilePromptB ) then
936 exit;
937
938 ImageOffsets := TList.Create;
939
940 AssignFile( F, FileName );
941 Rewrite( F );
942 WriteLn( F, ':userdoc.' );
943
944 // We can't tell if some levels of the contents were
945 // merged into the text of topics. So we just assume all are visible
946 WriteLn( F, ':docprof toc=123456.' );
947
948 ResourceIDs := TList.Create;
949
950 WriteLn( F, ':title.' + H.Title );
951
952 for i := 0 to H.TopicCount - 1 do
953 begin
954 T := H.Topics[ i ];
955
956 SetProgress( i div 2, H.TopicCount , 'Saving text...' );
957
958 WriteLn( F, '' );
959
960
961 if T.ContentsLevel = 0 then
962 begin
963 // perhaps it means footnote?
964 // Level := 1;
965 Write( F, ':fn id=fn' + IntToStr( i ) + '.' ); // use index as id
966
967 T.SaveToIPF( F, ImageOffsets );
968
969 WriteLn( F, '' );
970 WriteLn( F, ':efn.' );
971 end
972 else
973 begin
974 Write( F, ':h' + IntToStr( T.ContentsLevel ) );
975 Write( F, ' id=' + IntToStr( i ) ); // use index as id
976
977 H.FindResourceIDsForTopic( T, ResourceIDs );
978 if ResourceIDs.Count > 0 then
979 begin
980 Write( F, ' res=' + IntToStr( longint( ResourceIDs[ 0 ] ) ) );
981 end;
982
983 if not T.ShowInContents then
984 Write( F, ' hide' );
985
986 if T.ContentsGroupIndex > 0 then
987 Write( F, ' group=' + IntToStr( T.ContentsGroupIndex ) );
988
989 Write( F, '.' ); // end of header
990 WriteLn( F, T.Title );
991
992 T.SaveToIPF( F, ImageOffsets );
993 end;
994
995
996
997 end;
998
999 ResourceIDs.Destroy;
1000
1001 WriteLn( F, ':euserdoc.' );
1002 System.Close( F );
1003
1004 // Now write images
1005
1006 for i := 0 to ImageOffsets.Count - 1 do
1007 begin
1008 ImageOffset := longint( ImageOffsets[ i ] );
1009
1010 SetProgress( i div 2 + ImageOffsets.Count div 2,
1011 ImageOffsets.Count ,
1012 'Saving images...' );
1013
1014 Image := H.GetImage( ImageOffset );
1015
1016 if Image <> nil then
1017 begin
1018 Image.SaveToFile( ExtractFilePath( Filename )
1019 + 'img'
1020 + IntToStr( i )
1021 + '.bmp' );
1022 Image.Destroy;
1023 end;
1024
1025 end;
1026
1027 ResetProgress;
1028 SetStatus( 'Save complete' );
1029 ImageOffsets.Destroy;
1030End;
1031
1032Procedure TMainForm.DebugFindBinaryMIOnClick (Sender: TObject);
1033Var
1034 DataStr: string;
1035 data: array[ 0.. 255 ] of byte;
1036 DataLen: longint;
1037 FileIndex: longint;
1038 HelpFile: THelpFile;
1039 i: longint;
1040 Topic: TTopic;
1041
1042 tmpParts : TStringList;
1043Begin
1044 if not DoInputQuery( 'Binary Find',
1045 'Enter data to find (decimal, separate with spaces)',
1046 DataStr ) then
1047 exit;
1048
1049 tmpParts := TStringList.Create;
1050 StrExtractStringsIgnoreEmpty(tmpParts, DataStr, [' '], #0);
1051 for i := 0 to tmpParts.count-1 do
1052 begin
1053 Data[i] := StrToInt(tmpParts[i]);
1054 end;
1055 DataLen := tmpParts.count;
1056 tmpParts.Destroy;
1057
1058 ShowTab( piSearch );
1059 SearchResultsListBox.Clear;
1060
1061 for FileIndex := 0 to CurrentOpenFiles.Count - 1 do
1062 begin
1063 HelpFile := CurrentOpenFiles[ FileIndex ];
1064 for i := 0 to HelpFile.TopicCount -1 do
1065 begin
1066 Topic := HelpFile.Topics[ i ];
1067 if Topic.SearchForData( Addr(Data), DataLen) then
1068 begin
1069 SearchResultsListBox.Items.AddObject( Topic.Title, Topic );
1070 end;
1071
1072 end;
1073
1074 end;
1075
1076End;
1077
1078Procedure TMainForm.TopicByNameMIOnClick (Sender: TObject);
1079var
1080 TopicNameString: string;
1081Begin
1082 if not DoInputQuery( FindTopicNameTitle,
1083 FindTopicNamePrompt,
1084 TopicNameString ) then
1085 exit;
1086
1087 if not DisplayTopicByName( TopicNameString ) then
1088 if not DisplayTopicByGlobalName( TopicNameString ) then
1089 DoErrorDlg( FindTopicNameTitle,
1090 TopicNameNotFoundError );
1091End;
1092
1093Function TMainForm.pSharedStruct: TPNewHelpMgrSharedStruct;
1094begin
1095 Result := TPNewHelpMgrSharedStruct( SharedMemory.Data );
1096end;
1097
1098Procedure TMainForm.CopyLinkLocationPMIOnClick (Sender: TObject);
1099Begin
1100
1101End;
1102
1103Procedure TMainForm.HelpKeysMIOnClick (Sender: TObject);
1104Begin
1105// Application.Help( 10 );
1106End;
1107
1108Procedure TMainForm.MainFormOnCommand (Sender: TObject; Var Command: TCommand);
1109Begin
1110 case Command of
1111 kbF11:
1112 NavigatePreviousInContents;
1113
1114 kbF12:
1115 NavigateNextInContents;
1116
1117 kbF7,
1118 kbCtrlCLeft:
1119 NavigateBack;
1120
1121 kbF8:
1122 NavigateForward;
1123 end;
1124End;
1125
1126Procedure TMainForm.MainFormOnScan (Sender: TObject; Var KeyCode: TKeyCode);
1127Begin
1128End;
1129
1130Procedure TMainForm.ShowLeftPanelMIOnClick (Sender: TObject);
1131Begin
1132 ShowLeftPanel := not ShowLeftPanel;
1133End;
1134
1135Procedure TMainForm.CoolBarOnFontChange (Sender: TObject);
1136Begin
1137 SetApplicationFont( Coolbar.Font );
1138End;
1139
1140Procedure TMainForm.NotebookOnFontChange (Sender: TObject);
1141Begin
1142 SetApplicationFont( Notebook.Font );
1143End;
1144
1145Procedure TMainForm.TabSetOnFontChange (Sender: TObject);
1146Begin
1147 SetApplicationFont( TabSet.Font );
1148End;
1149
1150Procedure TMainForm.IndexListBoxOnFontChange (Sender: TObject);
1151Begin
1152 SetApplicationFont( IndexListBox.Font );
1153End;
1154
1155Procedure TMainForm.NotesListBoxOnFontChange (Sender: TObject);
1156Begin
1157 SetApplicationFont( NotesListBox.Font );
1158End;
1159
1160Procedure TMainForm.DisplayPanelOnFontChange (Sender: TObject);
1161Begin
1162 SetTopicFont( DisplayPanel.Font );
1163End;
1164
1165Procedure TMainForm.SetTopicFont( NewFont: TFont );
1166var
1167 ShiftPressed: boolean;
1168Begin
1169 if SettingFont or StartingUp then
1170 exit;
1171 LogEvent(LogSettings, 'SetTopicFont');
1172
1173 SettingFont := true;
1174
1175 ShiftPressed := ( WinGetKeyState( HWND_DESKTOP,
1176 VK_SHIFT ) and $8000 ) > 0;
1177 if ShiftPressed then
1178 Settings.FixedFont := NewFont
1179 else
1180 Settings.NormalFont := NewFont;
1181
1182 LogEvent(LogSettings, 'Saving settings');
1183
1184 SaveSettings;
1185 LogEvent(LogSettings, 'Applying settings');
1186 ApplySettings;
1187
1188 SettingFont := false;
1189 LogEvent(LogSettings, 'SetTopicFont done');
1190End;
1191
1192Procedure TMainForm.ContentsOutlineOnFontChange (Sender: TObject);
1193Begin
1194 SetApplicationFont( ContentsOutline.Font );
1195End;
1196
1197Procedure TMainForm.SetApplicationFont( NewFont: TFont );
1198Begin
1199 if ( not SettingFont ) and ( not StartingUp ) then
1200 begin
1201 Settings.Fonts[ ApplicationFontIndex ] := NewFont;
1202 SaveSettings;
1203 ApplySettings;
1204 SetLayout;
1205 end;
1206End;
1207
1208Procedure TMainForm.SearchResultsListBoxOnFontChange (Sender: TObject);
1209Begin
1210 SetApplicationFont( SearchResultsListBox.Font );
1211End;
1212
1213Procedure TMainForm.OnDragOverWindow(Sender: TObject; Source: TObject;
1214 X: LongInt; Y: LongInt; State: TDragState; Var Accept: Boolean);
1215Begin
1216 if Source is TExternalDragDropObject then
1217 Accept := true;
1218
1219End;
1220
1221Procedure TMainForm.OnDragDropToWindow(Sender: TObject; Source: TObject;
1222 X: LongInt; Y: LongInt);
1223Begin
1224 OpenDroppedFile( Source );
1225End;
1226
1227Procedure TMainForm.OnWindowTab( Sender: TObject );
1228Begin
1229 OnWindowBackTab( Sender ); // for now
1230End;
1231
1232Procedure TMainForm.OnWindowBackTab( Sender: TObject );
1233Begin
1234 case NoteBook.PageIndex of
1235 piContents:
1236 ContentsOutline.Focus;
1237 piIndex:
1238 IndexListBox.Focus;
1239 piSearch:
1240 SearchResultsListBox.Focus;
1241 piNotes:
1242 NotesListBox.Focus;
1243 end;
1244End;
1245
1246Procedure TMainForm.OnWindowFontChange( Sender: TObject );
1247begin
1248 if not DisplayingTopicWindow then
1249 SetTopicFont( TControl(Sender).Font );
1250end;
1251
1252Procedure TMainForm.DisplayPanelOnDragOver (Sender: TObject; Source: TObject;
1253 X: LongInt; Y: LongInt; State: TDragState; Var Accept: Boolean);
1254Begin
1255 if Source is TExternalDragDropObject then
1256 Accept := true;
1257End;
1258
1259Procedure TMainForm.NotesListBoxOnDragOver (Sender: TObject; Source: TObject;
1260 X: LongInt; Y: LongInt; State: TDragState; Var Accept: Boolean);
1261Begin
1262 if Source is TExternalDragDropObject then
1263 Accept := true;
1264End;
1265
1266Procedure TMainForm.DisplayPanelOnDragDrop (Sender: TObject; Source: TObject;
1267 X: LongInt; Y: LongInt);
1268Begin
1269 OpenDroppedFile( Source );
1270End;
1271
1272Procedure TMainForm.NotesListBoxOnDragDrop (Sender: TObject; Source: TObject;
1273 X: LongInt; Y: LongInt);
1274Begin
1275 OpenDroppedFile( Source );
1276End;
1277
1278Procedure TMainForm.SearchResultsListBoxOnDragDrop (Sender: TObject;
1279 Source: TObject; X: LongInt; Y: LongInt);
1280Begin
1281 OpenDroppedFile( Source );
1282End;
1283
1284Procedure TMainForm.SearchResultsListBoxOnDragOver (Sender: TObject;
1285 Source: TObject; X: LongInt; Y: LongInt; State: TDragState;
1286 Var Accept: Boolean);
1287Begin
1288 if Source is TExternalDragDropObject then
1289 Accept := true;
1290End;
1291
1292Procedure TMainForm.IndexListBoxOnDragDrop (Sender: TObject; Source: TObject;
1293 X: LongInt; Y: LongInt);
1294Begin
1295 OpenDroppedFile( Source );
1296End;
1297
1298Procedure TMainForm.IndexListBoxOnDragOver (Sender: TObject; Source: TObject;
1299 X: LongInt; Y: LongInt; State: TDragState; Var Accept: Boolean);
1300Begin
1301 if Source is TExternalDragDropObject then
1302 Accept := true;
1303End;
1304
1305Procedure TMainForm.ContentsOutlineOnDragOver (Sender: TObject;
1306 Source: TObject; X: LongInt; Y: LongInt; State: TDragState;
1307 Var Accept: Boolean);
1308Begin
1309 if Source is TExternalDragDropObject then
1310 Accept := true;
1311End;
1312
1313Procedure TMainForm.ContentsOutlineOnDragDrop (Sender: TObject;
1314 Source: TObject; X: LongInt; Y: LongInt);
1315Begin
1316 OpenDroppedFile( Source );
1317End;
1318
1319Procedure TMainForm.OpenDroppedFile( Source: TObject );
1320var
1321 DropObject: TExternalDragDropObject;
1322 LocaleName: String;
1323 MajorLanguage: String;
1324 MinorLanguage: String;
1325Begin
1326 if not ( Source is TExternalDragDropObject ) then
1327 // probably not needed, but crashes during drag drop completely
1328 // screw PM, so best to be sure!
1329 exit;
1330
1331 DropObject := Source as TExternalDragDropObject;
1332
1333 // See if it's a locale name (which reports as a bitmap file for some reason)
1334 if ( DropObject.ContainerName = '.') and
1335 ( DropObject.RenderString = '< DRM_OS2FILE, DRF_BITMAP >')
1336 then
1337 begin
1338 LocaleName := DropObject.SourceFilename;
1339 MajorLanguage := ExtractNextValue( LocaleName, '_' );
1340 if MajorLanguage <> '' then
1341 begin
1342 if MajorLanguage = 'en' then
1343 begin
1344 LoadLanguage('');
1345 exit;
1346 end;
1347 MinorLanguage := ExtractNextValue( LocaleName, '.' );
1348 if ( MinorLanguage <> '') and
1349 ( LoadAutoLanguage('newview', MajorLanguage + '_' + MinorLanguage ))
1350 then
1351 exit;
1352 if not LoadAutoLanguage('newview', MajorLanguage ) then
1353 LoadDefaultLanguage('newview');
1354 exit;
1355 end;
1356 end;
1357
1358 g_ExternalLinkFileName := AddDirectorySeparator( DropObject.ContainerName )
1359 + DropObject.SourceFilename;
1360 g_ExternalLinkTopic := '';
1361 g_ExternalLinkSourceFilename := ''; // don't care
1362
1363 g_ExternalLinkKeepCurrent := ( WinGetKeyState( HWND_DESKTOP,
1364 VK_SHIFT ) and $8000 ) > 0;
1365 PostMsg( Self.Handle,
1366 WM_FOLLOWEXTERNALLINK,
1367 0,
1368 0 );
1369
1370End;
1371
1372Procedure TMainForm.MainFormOnDragOver (Sender: TObject; Source: TObject;
1373 X: LongInt; Y: LongInt; State: TDragState; Var Accept: Boolean);
1374Begin
1375 Accept := true;
1376End;
1377
1378Procedure TMainForm.MainFormOnDragDrop (Sender: TObject; Source: TObject;
1379 X: LongInt; Y: LongInt);
1380Begin
1381End;
1382
1383Procedure TMainForm.ContentsOutlineOnItemClick (Node: TNode);
1384Begin
1385 DisplaySelectedContentsTopic;
1386End;
1387
1388Procedure TMainForm.SetMainCaption;
1389begin
1390 if ( Trim( MainTitle ) = '' )
1391 or ( StrEqualIgnoringCase( Trim( MainTitle ), HelpProgramTitle ) ) then
1392 // supress "Help - " or "Help - Help"
1393 Caption := HelpProgramTitle
1394 else
1395 Caption := HelpProgramTitle + ' - ' + MainTitle
1396end;
1397
1398Procedure TMainForm.OnLanguageEvent( Language: TLanguageFile;
1399 const Apply: boolean );
1400Begin
1401 // get rid of mru menu items
1402 DestroyListObjects( MRUMenuItems );
1403 MRUMenuItems.Clear;
1404
1405 Language.LoadComponentLanguage( self, Apply );
1406
1407 if Apply then
1408 begin
1409 // copy menu hints to toolbar hints
1410 Coolbar.Sections[ ciOpen ].Hint := OpenMI.Hint;
1411 Coolbar.Sections[ ciPrint ].Hint := PrintMI.Hint;
1412 Coolbar.Sections[ ciNavigator ].Hint := ShowLeftPanelMI.Hint;
1413 Coolbar.Sections[ ciBack ].Hint := NavigateBackMI.Hint;
1414 Coolbar.Sections[ ciForward ].Hint := NavigateForwardMI.Hint;
1415 Coolbar.Sections[ ciAddNote ].Hint := AddNoteMI.Hint;
1416 Coolbar.Sections[ ciAddBookmark ].Hint := AddBookmarkMI.Hint;
1417 Coolbar.Sections[ ciPrevious ].Hint := NavigatePreviousMI.Hint;
1418 Coolbar.Sections[ ciNext ].Hint := NavigateNextMI.Hint;
1419 Coolbar.Sections[ ciGlobalSearch ].Hint := GlobalSearchMI.Hint;
1420 end;
1421
1422 // Load strings referred to by code...
1423 // ----------------------------------------------------------
1424
1425 Language.LL( Apply, FileOpenTitle, 'FileOpenTitle', 'Open Help Files' );
1426 Language.LL( Apply, LoadingFileMsg, 'LoadingFileMsg', 'Loading file ' );
1427 Language.LL( Apply, HelpFileError, 'HelpFileError', 'Could not open ' );
1428 Language.LL( Apply, LoadingStatusDisplaying, 'LoadingStatusDisplaying', 'Displaying...' );
1429 Language.LL( Apply, LoadingStatusNotesAndBookmarks, 'LoadingStatusNotesAndBookmarks', 'Loading notes/bookmarks...' );
1430 Language.LL( Apply, LoadingStatusContents, 'LoadingStatusContents', 'Display contents... ' );
1431 Language.LL( Apply, LoadingStatusIndex, 'LoadingStatusIndex', 'Display index... ' );
1432 Language.LL( Apply, LoadingStatusDone, 'LoadingStatusDone', 'Done' );
1433
1434 Language.LL( Apply, HelpFilesDesc, 'HelpFilesDesc', 'Help Files (*.inf,*.hlp)' );
1435 Language.LL( Apply, AllFilesDesc, 'AllFilesDesc', 'All Files (*)' );
1436 Language.LL( Apply, LanguageFilesDesc, 'LanguageFilesDesc', 'NewView Language Files (*.lng)' );
1437
1438 Language.LL( Apply, SaveLanguageTitle, 'SaveLanguageTitle', 'Save/Update Language File' );
1439 Language.LL( Apply, OpenLanguageTitle, 'OpenLanguageTitle', 'Open Language File' );
1440 Language.LL( Apply, SaveLanguageError, 'SaveLanguageError', 'Error saving language file: ' );
1441
1442 Language.LL( Apply, HelpManagerVersionTitle, 'HelpManagerVersionTitle', 'Help Manager Version' );
1443
1444 Language.LL( Apply, FindResourceIDTitle, 'FindResourceIDTitle', 'Find Resource ID' );
1445 Language.LL( Apply, FindResourceIDPrompt, 'FindResourceIDPrompt', 'Enter the resource ID to find' );
1446 Language.LL( Apply, InvalidResourceIDError, 'InvalidResourceIDError', 'Invalid resource ID entered' );
1447 Language.LL( Apply, ResourceIDNotFoundError, 'ResourceIDNotFoundError', 'Resource ID not found' );
1448
1449 Language.LL( Apply, OpenSpecialTitle, 'OpenSpecialTitle', 'Open Special' );
1450 Language.LL( Apply, OpenSpecialPrompt, 'OpenSpecialPrompt', 'Enter help filename/environment variable name' );
1451
1452 Language.LL( Apply, PrintTopicTitle, 'PrintTopicTitle', 'Print Topic' );
1453 Language.LL( Apply, NoPrinterError, 'NoPrinterError', 'You don''t have a printer configured.' );
1454 Language.LL( Apply, SelectWindowToPrintError, 'SelectWindowToPrintError', 'You must select the window you want to print.' );
1455 Language.LL( Apply, PrintingError, 'PrintingError', 'Error while printing: ' );
1456 Language.LL( Apply, StoppingPrintMsg, 'StoppingPrintMsg', 'Stopping print...' );
1457 Language.LL( Apply, PrintStoppedMsg, 'PrintStoppedMsg', 'Printing stopped' );
1458 Language.LL( Apply, CheckStopPrintTitle, 'CheckStopPrintTitle', 'Stop Print?' );
1459 Language.LL( Apply, CheckStopPrintMsg, 'CheckStopPrintMsg', 'Printing is still in progress. It will be stopped if you close.' );
1460
1461 Language.LL( Apply, TopicInfoTitle, 'TopicInfo.Title', 'Topic Information' );
1462 Language.LL( Apply, TopicInfoTopicTitle, 'TopicInfo.TopicTitle', 'Title: ' );
1463 Language.LL( Apply, TopicInfoIndex, 'TopicInfo.Index', 'Index: ' );
1464 Language.LL( Apply, TopicInfoFile, 'TopicInfo.File', 'File: ' );
1465 Language.LL( Apply, TopicInfoResourceIDs, 'TopicInfo.ResourceIDs', 'Resource IDs:' );
1466 Language.LL( Apply, TopicInfoNoResourceIDs, 'TopicInfo.NoResourceIDs', ' (None)' );
1467
1468 Language.LL( Apply, ParameterCountLabel, 'ParameterCountLabel', 'Parameter Count: ' );
1469
1470 Language.LL( Apply, NewViewHelpTitle, 'NewViewHelpTitle', 'NewView Help' );
1471 Language.LL( Apply, AlreadyNewviewHelp, 'AlreadyNewviewHelp', 'You are already viewing the NewView help file' );
1472 Language.LL( Apply, NewViewHelpNotFound, 'NewViewHelpNotFound', 'Couldn''t find the NewView helpfile: ' );
1473
1474 Language.LL( Apply, InvalidLinkErrorTitle, 'InvalidLinkErrorTitle', 'Invalid Link' );
1475 Language.LL( Apply, InvalidLinkError, 'InvalidLinkError', 'Cannot follow link to nonexistent topic' );
1476 Language.LL( Apply, InvalidResourceIDLinkErrorA, 'InvalidResourceIDLinkErrorA', 'Could not find linked topic (Resource #' );
1477 Language.LL( Apply, InvalidResourceIDLinkErrorB, 'InvalidResourceIDLinkErrorB', '). This may be from another file.' );
1478
1479 Language.LL( Apply, OpenedTopicMsg, 'OpenedTopicMsg', 'Opened topic #' );
1480
1481 Language.LL( Apply, AddNoteTitle, 'AddNoteTitle', 'Add Note' );
1482 Language.LL( Apply, AddNoteCursorError, 'AddNoteCursorError', 'Before adding a note, position the cursor where you want the note to be placed.' );
1483 Language.LL( Apply, NoteWithinNoteError, 'NoteWithinNoteError', 'You can''t add a note within a link or another note' );
1484 Language.LL( Apply, LoadNotesTitle, 'LoadNotesTitle', 'Load Notes' );
1485 Language.LL( Apply, LoadNotesError, 'LoadNotesError', 'Error loading notes from ' );
1486 Language.LL( Apply, SaveNotesTitle, 'SaveNotesTitle', 'Save Notes' );
1487 Language.LL( Apply, SaveNotesError, 'SaveNotesError', 'Error saving notes to ' );
1488
1489 Language.LL( Apply, UntitledBookmarkName, 'UntitledBookmarkName', '(Untitled)' );
1490 Language.LL( Apply, LoadBookmarksTitle, 'LoadBookmarksTitle', 'Load Bookmarks' );
1491 Language.LL( Apply, LoadBookmarksError, 'LoadBookmarksError', 'Could not load bookmarks: ' );
1492 Language.LL( Apply, SaveBookmarksTitle, 'SaveBookmarksTitle', 'Save Bookmarks' );
1493 Language.LL( Apply, SaveBookmarksError, 'SaveBookmarksError', 'Could not save bookmarks: ' );
1494
1495 Language.LL( Apply, ApplicationErrorTitle, 'ApplicationErrorTitle', 'Application Error - Close?' );
1496 Language.LL( Apply, ApplicationErrorA, 'ApplicationErrorA', 'This application has crashed. ' );
1497 Language.LL( Apply, ApplicationErrorB, 'ApplicationErrorB', '(Details logged to ' );
1498 Language.LL( Apply, ApplicationErrorC, 'ApplicationErrorC', 'Close application? ' );
1499
1500 Language.LL( Apply, EnvironmentVarErrorTitle, 'EnvironmentVarErrorTitle', 'Environment Variable Warning' );
1501 Language.LL( Apply, EnvironmentVarError,
1502 'EnvironmentVarError',
1503 'NewView found a problem with environment variables. '
1504 + 'These are used when finding help files. '
1505 + 'You may have problems launching help.' );
1506 Language.LL( Apply, EnvironmentVarUndefined, 'EnvironmentVarUndefined', 'Undefined: ' );
1507
1508 Language.LL( Apply, FindTitle, 'FindTitle', 'Find' );
1509 Language.LL( Apply, FindSelectWindowError, 'FindSelectWindowError', 'Click in a window first' );
1510 Language.LL( Apply, FindPrompt, 'FindPrompt', 'Enter the text to find' );
1511 Language.LL( Apply, TextNotFoundMsg, 'TextNotFoundMsg', 'Text not found' );
1512
1513 Language.LL( Apply, FilesInfoTitle, 'FilesInfoTitle', 'Open Files Information' );
1514 Language.LL( Apply, FilesInfoOverallTitle, 'FilesInfoOverallTitle', 'Title: ' );
1515 Language.LL( Apply, FilesInfoFilename, 'FilesInfoFilename', 'Filename: ' );
1516 Language.LL( Apply, FilesInfoFileTitle, 'FilesInfoFileTitle', ' Title: ' );
1517 Language.LL( Apply, FilesInfoTopicCount, 'FilesInfoTopicCount', ' Topic Count: ' );
1518 Language.LL( Apply, FilesInfoIndexCount, 'FilesInfoIndexCount', ' Index Count: ' );
1519 Language.LL( Apply, FilesInfoDictionaryCount, 'FilesInfoDictionaryCount', ' Dictionary Count: ' );
1520 Language.LL( Apply, FilesInfoFileSize, 'FilesInfoFileSize', ' Size: ' );
1521 Language.LL( Apply, FilesInfoTotalTopicCount, 'FilesInfoTotalTopicCount', 'Total Topic Count: ' );
1522 Language.LL( Apply, FilesInfoTotalIndexCount, 'FilesInfoTotalIndexCount', 'Total Index Count: ' );
1523 Language.LL( Apply, FilesInfoTotalFileSize, 'FilesInfoTotalFileSize', 'Total File Size: ' );
1524
1525 Language.LL( Apply, SearchTitle, 'SearchTitle', 'Search' );
1526 Language.LL( Apply, SearchSyntaxError, 'SearchSyntaxError', 'Error in search syntax: ' );
1527 Language.LL( Apply, SearchingMsg, 'SearchingMsg', 'Searching...' );
1528 Language.LL( Apply, NoSearchMatchesMsg, 'NoSearchMatchesMsg', 'No matches found for ' );
1529 Language.LL( Apply, SearchFoundMsgA, 'SearchFoundMsgA', 'Found ' );
1530 Language.LL( Apply, SearchFoundMsgB, 'SearchFoundMsgB', ' matches for ' );
1531
1532 Language.LL( Apply, FileSaveTitle, 'FileSaveTitle', 'Save Topic' );
1533 Language.LL( Apply, FileSaveSelectWindowError, 'FileSaveSelectWindowError', 'Before saving, click in the window you want to save.' );
1534 Language.LL( Apply, DefaultSaveTopicFilename, 'DefaultSaveTopicFilename', 'topic.txt' );
1535
1536 Language.LL( Apply, ReplaceFilePromptA, 'ReplaceFilePromptA', 'Replace existing file ' );
1537 Language.LL( Apply, ReplaceFilePromptB, 'ReplaceFilePromptB', '?' );
1538 Language.LL( Apply, UnableToSaveError, 'UnableToSaveError', 'Unable to save file: ' );
1539
1540 Language.LL( Apply, UsageTitle, 'UsageTitle', 'NewView Command Line' );
1541 Language.LL( Apply, UsageText1, 'UsageText1', 'Usage: ' );
1542 Language.LL( Apply, UsageText2, 'UsageText2', 'NewView <filename> [<topic>]' );
1543 Language.LL( Apply, UsageText3, 'UsageText3', ' /s Do search for <topic>' );
1544 Language.LL( Apply, UsageText4, 'UsageText4', ' /g Do global search for <topic>' );
1545 Language.LL( Apply, UsageText5, 'UsageText5', ' /pos:l,b,w,h Set window position' );
1546 Language.LL( Apply, UsageText6, 'UsageText6', ' /lang:<lang> Load UI language' );
1547 Language.LL( Apply, UsageText7, 'UsageText7', ' /title:<title> Set window title' );
1548 Language.LL( Apply, UsageText8, 'UsageText8', 'See help for details' );
1549
1550 Language.LL( Apply, GoBackHint, 'GoBackHint', 'Go back to ' );
1551
1552 Language.LL( Apply, SelectAllTitle, 'SelectAllTitle', 'Select All' );
1553 Language.LL( Apply, SelectAllWindowError, 'SelectAllWindowError', 'Click in a text window first' );
1554
1555 Language.LL( Apply, EditNoteMsg, 'EditNoteMsg', 'Click to edit note' );
1556 Language.LL( Apply, ExternalLinkMsg, 'ExternalLinkMsg', 'Link to another file' );
1557 Language.LL( Apply, LinkMsg, 'LinkMsg', 'Link to' );
1558 Language.LL( Apply, UnknownLinkMsg, 'UnknownLinkMsg', 'Unknown link' );
1559 Language.LL( Apply, FootnoteMsg, 'FootnoteMsg', 'Footnote' );
1560
1561 Language.LL( Apply, ExternalLinkTitle, 'ExternalLinkTitle', 'File Link' );
1562 Language.LL( Apply, ExternalLinkError, 'ExternalLinkError', 'Sorry, this is a link to another file, which is not currently implemented in NewView' );
1563
1564 Language.LL( Apply, MRUMultipleFilesHint, 'MRUMultipleFilesHint', 'files' );
1565 Language.LL( Apply, HelpProgramTitle, 'HelpProgramTitle', 'Help' );
1566
1567 Language.LL( Apply, WindowsHelpTitle, 'WindowsHelpTitle', 'Windows Help' );
1568 Language.LL( Apply,
1569 WindowsHelpPrompt,
1570 'WindowsHelpPrompt',
1571 'This file is a Windows help file. '
1572 + 'Would you like to start Windows Help viewer?' );
1573
1574 Language.LL( Apply, ErrorTitle, 'ErrorTitle', 'Error' );
1575
1576 Language.LL( Apply, FindTopicNameTitle, 'FindTopicNameTitle', 'Find Topic By Name' );
1577 Language.LL( Apply, FindTopicNamePrompt, 'FindTopicNamePrompt', 'Enter the topic name to search for' );
1578 Language.LL( Apply, TopicNameNotFoundError, 'TopicNameNotFoundError', 'Topic name not found' );
1579 Language.LL( Apply, SplitBarDblClickToShow, 'SplitBarDblClickToShow', 'Double-click to show left panel' );
1580 Language.LL( Apply, SplitBarDblClickToHide, 'SplitBarDblClickToHide', 'Double-click to hide left panel' );
1581
1582 SetMainCaption;
1583 CreateMRUMenuItems;
1584
1585 // ----------------------------------------------------------
1586end;
1587
1588Procedure TMainForm.DebugLoadLanguageMIOnClick (Sender: TObject);
1589Var
1590 Dir: string;
1591 Filename: string;
1592Begin
1593 Dir := GetApplicationDir;
1594 if not DoOpenFileDialog( OpenLanguageTitle,
1595 LanguageFilesDesc
1596 + '|*.lng|'
1597 + AllFilesDesc
1598 + '|*',
1599 '*.lng',
1600 Dir,
1601 Filename ) then
1602 exit;
1603
1604 LoadLanguage( Filename );
1605End;
1606
1607Procedure TMainForm.DebugSaveLanguageFileMIOnClick (Sender: TObject);
1608Var
1609 LanguageFile: TLanguageFile;
1610 Dir: string;
1611 Filename: string;
1612Begin
1613 Dir := GetApplicationDir;
1614 if not DoSaveFileDialog( SaveLanguageTitle,
1615 LanguageFilesDesc
1616 + '|*.lng|'
1617 + AllFilesDesc
1618 + '|*',
1619 '*.lng',
1620 Dir,
1621 Filename ) then
1622 exit;
1623
1624 // get rid of mru menu items so they don't clutter the language file
1625 DestroyListObjects( MRUMenuItems );
1626 MRUMenuItems.Clear;
1627
1628 try
1629 LanguageFile := TLanguageFile.Create( Filename );
1630
1631 UpdateLanguage( LanguageFile );
1632 except
1633 on E: Exception do
1634 begin
1635 DoErrorDlg( SaveLanguageTitle,
1636 SaveLanguageError + E.Message );
1637 exit;
1638 end;
1639 end;
1640
1641 LanguageFile.Destroy;
1642
1643 CreateMRUMenuItems;
1644End;
1645
1646Procedure TMainForm.SearchResultsListBoxOnClick (Sender: TObject);
1647Begin
1648 DisplaySelectedSearchResultTopic;
1649End;
1650
1651Procedure TMainForm.VSplitBarOnDblClick (Sender: TObject);
1652Begin
1653 ShowLeftPanel := not ShowLeftPanel;
1654End;
1655
1656Procedure TMainForm.DebugHelpManagerVersionMIOnClick (Sender: TObject);
1657Begin
1658 DoMessageDlg( HelpManagerVersionTitle,
1659 HelpManagerVersion );
1660End;
1661
1662Procedure TMainForm.DebugTopicByResourceIDMIOnClick (Sender: TObject);
1663var
1664 ResourceIDString: string;
1665 ResourceID: USHORT;
1666Begin
1667 if not DoInputQuery( FindResourceIDTitle,
1668 FindResourceIDPrompt,
1669 ResourceIDString ) then
1670 exit;
1671 try
1672 ResourceID := StrToInt( ResourceIDString );
1673 except
1674 DoErrorDlg( FindResourceIDTitle,
1675 InvalidResourceIDError );
1676 exit;
1677 end;
1678
1679 if not DisplayTopicByResourceID( ResourceID ) then
1680 DoErrorDlg( FindResourceIDTitle,
1681 ResourceIDNotFoundError );
1682End;
1683
1684Procedure TMainForm.ViewHighlightSearchWordsMIOnClick (Sender: TObject);
1685Begin
1686 ViewHighlightSearchWordsMI.Checked := not ViewHighlightSearchWordsMI.Checked;
1687 RefreshWindows( Windows );
1688End;
1689
1690Procedure TMainForm.FileNewWindowMIOnClick (Sender: TObject);
1691Begin
1692 Exec( GetApplicationFilename, '' );
1693End;
1694
1695Function TMainForm.OpenFilesFromTextList( const TextList: string;
1696 const DisplayFirstTopic: boolean ): boolean;
1697var
1698 Filenames: TStringList;
1699begin
1700 Filenames := TStringList.Create;
1701 StrExtractStringsIgnoreEmpty(Filenames, TextList, ['+'], #0);
1702 if Filenames.Count > 0 then
1703 begin
1704 result := OpenFiles( Filenames, '', DisplayFirstTopic );
1705 end
1706 else
1707 begin
1708 CloseFile;
1709 end;
1710 Filenames.Destroy;
1711end;
1712
1713Procedure TMainForm.OpenSpecialMIOnClick (Sender: TObject);
1714var
1715 Parameter: string;
1716Begin
1717 if not OKToCloseFile then
1718 exit;
1719
1720 if DoInputQuery( OpenSpecialTitle,
1721 OpenSpecialPrompt,
1722 Parameter ) then
1723 begin
1724 if OpenFilesFromTextList( Parameter, true ) then
1725 begin
1726 ClearHelpManager;
1727 end;
1728 end;
1729End;
1730
1731Procedure TMainForm.NotesListBoxOnScan (Sender: TObject;
1732 Var KeyCode: TKeyCode);
1733Begin
1734 if KeyCode in [ kbDel, kbBkSp ] then
1735 if NotesListBox.ItemIndex <> -1 then
1736 DeleteNote( NotesListBox.ItemIndex );
1737End;
1738
1739Procedure TMainForm.ViewPopupMenuOnPopup (Sender: TObject);
1740var
1741 Window: THelpWindow;
1742Begin
1743 Window := GetActiveWindow;
1744 if Window = nil then
1745 begin
1746 SearchPMI.Enabled := false;
1747 exit;
1748 end;
1749 SearchPMI.Enabled := Window.View.SelectionLength > 0;
1750End;
1751
1752Procedure TMainForm.SearchPMIOnClick (Sender: TObject);
1753var
1754 Window: THelpWindow;
1755Begin
1756 Window := GetActiveWindow;
1757 if Window = nil then
1758 exit;
1759
1760 SearchFor( Window.View.GetSelectionAsString );
1761end;
1762
1763function TMainForm.DisplayTopicByGlobalName( const TopicName: string ): boolean;
1764var
1765 Topic: TTopic;
1766begin
1767 Topic := FindTopicByGlobalName( TopicName );
1768 if Topic = nil then
1769 begin
1770 Result := false;
1771 exit;
1772 end;
1773
1774 result := true;
1775
1776 DisplayTopic( Topic );
1777end;
1778
1779function TMainForm.DisplayTopicByName( const TopicName: string ): boolean;
1780var
1781 Topic: TTopic;
1782begin
1783 Topic := FindTopicByName( TopicName );
1784 if Topic = nil then
1785 begin
1786 Result := false;
1787 exit;
1788 end;
1789
1790 result := true;
1791
1792 DisplayTopic( Topic );
1793end;
1794
1795function TMainForm.DisplayTopicByResourceID( ID: uint16 ): boolean;
1796var
1797 Topic: TTopic;
1798begin
1799 LogEvent(LogDebug, 'DisplayTopicByResourceID id:' + IntToStr(ID));
1800 Topic := FindTopicByResourceID( ID );
1801 if Topic = nil then
1802 begin
1803 LogEvent(LogDebug, 'DisplayTopicByResourceID - topic not found');
1804 Result := false;
1805 exit;
1806 end;
1807
1808 result := true;
1809
1810 LogEvent(LogDebug, 'DisplayTopicByResourceID topic: "' + Topic.Title + '"');
1811 DisplayTopic( Topic );
1812end;
1813
1814Procedure TMainForm.ViewSourceMIOnClick (Sender: TObject);
1815var
1816 Window: THelpWindow;
1817Begin
1818 Window := GetActiveWindow;
1819 if Window = nil then
1820 exit;
1821 InformationForm.FText := Window.View.Text;
1822 InformationForm.ShowModal;
1823End;
1824
1825Procedure TMainForm.PrintMIOnClick (Sender: TObject);
1826Begin
1827 PrintTopics;
1828End;
1829
1830type
1831 TPrintSingle = class
1832 Topic: TTopic;
1833 end;
1834
1835 TPrintList = class
1836 Topics: TList;
1837 constructor Create;
1838 destructor Destroy; override;
1839 end;
1840
1841 TPrintAll = class
1842 end;
1843
1844constructor TPrintList.Create;
1845begin
1846 Topics := TList.Create;
1847end;
1848
1849destructor TPrintList.Destroy;
1850begin
1851 Topics.Destroy;
1852end;
1853
1854// Recursive
1855Procedure GetTopicsInWindows( Windows: TList;
1856 Topics: TList );
1857var
1858 Window: THelpWindow;
1859 i: longint;
1860begin
1861 for i := 0 to Windows.Count - 1 do
1862 begin
1863 Window := Windows[ i ];
1864 Topics.Add( Window.Topic );
1865 GetTopicsInWindows( Window.ChildWindows, Topics );
1866 end;
1867end;
1868
1869Procedure TMainForm.PrintTopics;
1870var
1871 Window: THelpWindow;
1872 PrintParameters: TObject;
1873Begin
1874 if Printer.Printers.Count = 0 then
1875 begin
1876 DoErrorDlg( PrintTopicTitle,
1877 NoPrinterError );
1878 exit;
1879 end;
1880
1881 if NewViewPrintDialog.ShowModal <> mrOK then
1882 exit;
1883
1884 if PrintThread = nil then
1885 begin
1886 PrintThread := TGenericThreadManager.Create( self );
1887 PrintThread.OnProgressUpdate := OnPrintProgress;
1888 PrintThread.OnJobComplete := OnPrintComplete;
1889
1890 end;
1891
1892 case NewViewPrintDialog.WhatToPrintRadioGroup.ItemIndex of
1893 0:
1894 begin
1895 PrintParameters := TPrintSingle.Create;
1896 Window := GetActiveWindow;
1897 TPrintSingle( PrintParameters ).Topic := Window.Topic;
1898 end;
1899
1900 1:
1901 begin
1902 PrintParameters := TPrintList.Create;
1903 GetTopicsInWindows( Windows,
1904 TPrintList( PrintParameters ).Topics );
1905 end;
1906
1907 2:
1908 begin
1909 PrintParameters := TPrintAll.Create;
1910 end;
1911 end;
1912
1913 PrintThread.StartJob( DoPrinting, PrintParameters );
1914
1915 SetStatus( 'Printing...' );
1916end;
1917
1918procedure PrintTopic( Topic: TTopic;
1919 RichTextSettings: TRichTextSettings;
1920 Var PageY: longint );
1921var
1922 TopicText: TAstring;
1923 TitleText: TAString;
1924 ImageOffsets: TList;
1925 Images: TImageList;
1926begin
1927 TopicText := TAstring.Create;
1928 Images := TImageList.Create( nil );
1929 TitleText := TAString.Create;
1930 ImageOffsets := TList.Create;
1931
1932 TitleText.AddString( '<leftmargin 1><h1>'
1933 + Topic.Title
1934 + '</h>'
1935 + #10
1936 + #10 );
1937 PrintRichText( TitleText.AsPChar,
1938 Images,
1939 RichTextSettings,
1940 PageY );
1941
1942 Topic.GetText( nil, // no highlights
1943 false, // no codes
1944 false, // no word separators
1945 TopicText, // text to print
1946 ImageOffsets, // image offsets
1947 nil ); // no highlight matches required
1948
1949 THelpFile( Topic.HelpFile ).GetImages( ImageOffsets,
1950 Images );
1951
1952 PrintRichText( TopicText.AsPChar,
1953 Images,
1954 RichTextSettings,
1955 PageY );
1956
1957 TitleText.Clear;
1958 TitleText.AddString( #10
1959 + '<leftmargin 1><align center>'
1960 + '--------------------------------------------'
1961 + #10
1962 + #10 );
1963 PrintRichText( TitleText.AsPChar,
1964 Images,
1965 RichTextSettings,
1966 PageY );
1967
1968 ImageOffsets.Destroy;
1969 TitleText.Destroy;
1970 Images.Destroy;
1971 TopicText.Destroy;
1972end;
1973
1974function TMainForm.DoPrinting( Parameters: TObject ): TObject;
1975var
1976 PrintSingle: TPrintSingle;
1977 PrintList: TPrintList;
1978 PageY: longint;
1979 RichTextSettings: TRichTextSettings;
1980 PrinterResolution: longint;
1981 MarginSize: longint;
1982
1983 HelpFile: THelpFile;
1984
1985 FileIndex: longint;
1986 TopicIndex: longint;
1987
1988 TotalTopics: longint;
1989 TotalTopicIndex: longint;
1990begin
1991 PrintSingle := nil;
1992 PrintList := nil;
1993
1994 if Parameters is TPrintSingle then
1995 PrintSingle := Parameters as TPrintSingle
1996 else if Parameters is TPrintList then
1997 PrintList := Parameters as TPrintList;
1998
1999 if Parameters is TPrintSingle then
2000 Printer.Title := PrintSingle.Topic.Title
2001 else
2002 Printer.Title := MainTitle;
2003
2004 Printer.BeginDoc;
2005
2006 PageY := Printer.PageHeight - 1;
2007
2008 RichTextSettings := TRichTextSettings.Create( nil );
2009 RichTextSettings.NormalFont := Settings.NormalFont;
2010 RichTextSettings.FixedFont := Settings.FixedFont;
2011
2012 // set half inch margins
2013 PrinterResolution := Printer.Canvas.HorizontalResolution; // pixels per meter!
2014 MarginSize := Round( PrinterResolution * 0.0125 ); // 12.5 mm = 0.5 inch
2015 RichTextSettings.Margins := Rect( MarginSize,
2016 MarginSize,
2017 MarginSize,
2018 MarginSize );
2019
2020 try
2021 if Parameters is TPrintSingle then
2022 begin
2023 PrintTopic( PrintSingle.Topic, RichTextSettings, PageY );
2024 end
2025
2026 else if Parameters is TPrintList then
2027 begin
2028 for TopicIndex := 0 to PrintList.Topics.Count -1 do
2029 begin
2030 PrintThread.UpdateProgress( TopicIndex, PrintList.Topics.Count, 'Printing' );
2031
2032 PrintTopic( PrintList.Topics[ TopicIndex ] , RichTextSettings, PageY );
2033
2034 if PrintThread.StopRequested then
2035 break;
2036 end
2037 end
2038
2039 else if Parameters is TPrintAll then
2040 begin
2041 // first count up total number of topics.
2042 TotalTopics := 0;
2043 for FileIndex := 0 to CurrentOpenFiles.Count - 1 do
2044 begin
2045 HelpFile := CurrentOpenFiles[ FileIndex ];
2046 inc( TotalTopics, HelpFile.TopicCount );
2047 end;
2048
2049 TotalTopicIndex := 0;
2050 for FileIndex := 0 to CurrentOpenFiles.Count - 1 do
2051 begin
2052 HelpFile := CurrentOpenFiles[ FileIndex ];
2053 for TopicIndex := 0 to HelpFile.TopicCount - 1 do
2054 begin
2055 PrintThread.UpdateProgress( TotalTopicIndex, TotalTopics, 'Printing' );
2056 PrintTopic( HelpFile.Topics[ TopicIndex ], RichTextSettings, PageY );
2057 if PrintThread.StopRequested then
2058 break;
2059 inc( TotalTopicIndex );
2060 end;
2061 end;
2062 end;
2063 except
2064 on E: EPrinter do
2065 begin
2066 DoErrorDlg( PrintTopicTitle,
2067 PrintingError + E.Message );
2068 end;
2069 end;
2070
2071 Printer.EndDoc;
2072 result := nil;
2073End;
2074
2075procedure TMainForm.OnPrintProgress( n, outof: integer;
2076 Message: string );
2077begin
2078 SetProgress( n, outof, message );
2079end;
2080
2081procedure TMainForm.OnPrintComplete( Dummy: TObject );
2082begin
2083 SetStatus( 'Printing complete' );
2084 ResetProgress;
2085end;
2086
2087// --------------------------------------------------
2088
2089Procedure TMainForm.DebugShowWordSeparatorsMIOnClick (Sender: TObject);
2090Begin
2091 DebugShowWordSeparatorsMI.Checked := not DebugShowWordSeparatorsMI.Checked;
2092 RefreshWindows( Windows );
2093End;
2094
2095Procedure TMainForm.DebugStressTestMIOnClick (Sender: TObject);
2096var
2097 i: longint;
2098 NString: string;
2099 N: longint;
2100Begin
2101 if not DoInputQuery( 'Stress Test',
2102 'Repititions?',
2103 NString ) then
2104 exit;
2105 N := StrToIntDef( NString, 1 );
2106 for i := 0 to N - 1 do
2107 begin
2108 ContentsOutline.GotoFirstNode;
2109 repeat
2110 DisplaySelectedContentsTopic;
2111 Application.ProcessMessages;
2112 until not ContentsOutline.GotoNextNodeDown;
2113 end;
2114End;
2115
2116// Find topic specified by global name, in all open files
2117Function TMainForm.FindTopicByGlobalName( const Name: string ): TTopic;
2118var
2119 FileIndex: longint;
2120 HelpFile: THelpFile;
2121begin
2122 Result := nil;
2123
2124 for FileIndex := 0 to CurrentOpenFiles.Count - 1 do
2125 begin
2126 HelpFile := CurrentOpenFiles[ FileIndex ];
2127 Result := HelpFile.FindTopicByGlobalName( Name );
2128 if Result <> nil then
2129 // found
2130 exit;
2131 end;
2132
2133 // not found.
2134 Result := nil;
2135end;
2136
2137// Find topic specified by numeric resource ID, in all open files
2138Function TMainForm.FindTopicByResourceID( ID: uint16 ): TTopic;
2139var
2140 FileIndex: longint;
2141 HelpFile: THelpFile;
2142begin
2143 for FileIndex := 0 to CurrentOpenFiles.Count - 1 do
2144 begin
2145 HelpFile := CurrentOpenFiles[ FileIndex ];
2146
2147 Result := HelpFile.FindTopicByResourceID( ID );
2148 if Result <> nil then
2149 // found
2150 exit;
2151 end;
2152
2153 // not found.
2154 Result := nil;
2155end;
2156
2157// Find topic specified by text name, in all open files
2158Function TMainForm.FindTopicByName( const Name: string ): TTopic;
2159var
2160 FileIndex: longint;
2161 HelpFile: THelpFile;
2162begin
2163 Result := nil;
2164
2165 for FileIndex := 0 to CurrentOpenFiles.Count - 1 do
2166 begin
2167 HelpFile := CurrentOpenFiles[ FileIndex ];
2168 Result := HelpFile.FindTopicByLocalName( Name );
2169 if Result <> nil then
2170 // found
2171 exit;
2172 end;
2173
2174 // not found.
2175 Result := nil;
2176end;
2177
2178// Find the target topic for the given link
2179Function TMainForm.FindTopicForLink( Link: THelpLink ): TTopic;
2180var
2181 HelpFile: THelpFile;
2182begin
2183 HelpFile := Link.HelpFile as THelpFile;
2184 if Link is TFootnoteHelpLink then
2185 begin
2186 Result := HelpFile.Topics[ TFootnoteHelpLink( Link ).TopicIndex ];
2187 end
2188 else if Link is TInternalHelpLink then
2189 begin
2190 Result := HelpFile.Topics[ TInternalHelpLink( Link ).TopicIndex ];
2191 end
2192 else if Link is THelpLinkByResourceID then
2193 begin
2194 Result := FindTopicByResourceID( THelpLinkByResourceID( Link ).ResourceID );
2195 end
2196end;
2197
2198Procedure TMainForm.TopicPropertiesPMIOnClick (Sender: TObject);
2199var
2200 Window: THelpWindow;
2201 Topic: TTopic;
2202 HelpFile: THelpFile;
2203 ResourceIDs: TList;
2204 i: longint;
2205Begin
2206 Window := GetActiveWindow;
2207 if Window = nil then
2208 exit;
2209 Topic := Window.Topic;
2210 HelpFile := Topic.HelpFile as THelpFile;
2211
2212 ResourceIDs := TList.Create;
2213 HelpFile.FindResourceIDsForTopic( Topic,
2214 ResourceIDs );
2215
2216 with InformationForm.InformationMemo do
2217 begin
2218 Lines.Clear;
2219 Lines.Add( TopicInfoTitle );
2220 Lines.Add( TopicInfoTopicTitle + Topic.Title );
2221 Lines.Add( TopicInfoIndex + IntToStr( Topic.Index ) );
2222 Lines.Add( TopicInfoFile + HelpFile.Filename );
2223 Lines.Add( TopicInfoResourceIDs );
2224 for i := 0 to ResourceIDs.Count - 1 do
2225 Lines.Add( ' ' + IntToStr( longint( ResourceIDs[ i ] ) ) );
2226 if ResourceIDs.Count = 0 then
2227 Lines.Add( TopicInfoNoResourceIDs );
2228 end;
2229 ResourceIDs.Destroy;
2230
2231 InformationForm.ShowModal;
2232End;
2233Procedure TMainForm.NavigateForwardMIOnClick (Sender: TObject);
2234Begin
2235 NavigateForward;
2236End;
2237
2238Procedure TMainForm.FocusFirstHelpWindow;
2239begin
2240 if Windows.Count > 0 then
2241 THelpWindow( Windows[ 0 ] ).View.Focus;
2242end;
2243
2244Procedure TMainForm.IndexListBoxOnScan (Sender: TObject;
2245 Var KeyCode: TKeyCode);
2246Begin
2247 case KeyCode of
2248 kbTab:
2249 begin
2250 FocusFirstHelpWindow;
2251 KeyCode := kbNull;
2252 end;
2253 kb_VK + VK_NEWLINE:
2254 DisplaySelectedIndexTopic;
2255 end;
2256End;
2257
2258Procedure TMainForm.SearchResultsListBoxOnScan (Sender: TObject;
2259 Var KeyCode: TKeyCode);
2260Begin
2261 case KeyCode of
2262 kbTab:
2263 begin
2264 FocusFirstHelpWindow;
2265 KeyCode := kbNull;
2266 end;
2267
2268 kb_VK + VK_NEWLINE:
2269 DisplaySelectedSearchResultTopic;
2270 end;
2271End;
2272
2273Procedure TMainForm.ContentsOutlineOnScan (Sender: TObject;
2274 Var KeyCode: TKeyCode);
2275Begin
2276 case KeyCode of
2277 kbTab:
2278 begin
2279 FocusFirstHelpWindow;
2280 KeyCode := kbNull;
2281 end;
2282 kb_VK + VK_NEWLINE:
2283 DisplaySelectedContentsTopic;
2284 end;
2285End;
2286
2287Procedure TMainForm.ToolsOptionsMIOnClick (Sender: TObject);
2288Begin
2289 DoOptions;
2290End;
2291
2292Procedure TMainForm.EditGlobalSearchMIOnClick (Sender: TObject);
2293Begin
2294 DoGlobalSearch( '' );
2295End;
2296
2297Procedure TMainForm.ViewExpandAllMIOnClick (Sender: TObject);
2298Begin
2299 DisplayContents;
2300 ContentsOutline.ExpandAll;
2301End;
2302
2303Procedure TMainForm.DebugShowParamsMIOnClick (Sender: TObject);
2304Begin
2305 with InformationForm.InformationMemo do
2306 begin
2307 Lines.Clear;
2308 Lines.Add('');
2309
2310 CmdLineParameters.writeDetailsTo(Lines);
2311 writeSettingsDetailsTo(Lines);
2312 end;
2313
2314 InformationForm.ShowModal;
2315End;
2316
2317Procedure TMainForm.EditBookmarksMIOnClick (Sender: TObject);
2318Begin
2319 BookmarksForm.BookmarkList := Bookmarks;
2320 BookmarksForm.OpenBookmarkCallback := NavigateToBookmark;
2321 BookmarksForm.BookmarksChangedCallback := OnBookmarksChanged;
2322 BookmarksForm.Show;
2323
2324 // Since we are showing a nonmodal dialog, set the PM owner window
2325 // so that the bookmarks form remains on top.
2326 WinSetOwner( BookmarksForm.Frame.Handle,
2327 Frame.Handle );
2328End;
2329
2330Procedure TMainForm.CopyPMIOnClick (Sender: TObject);
2331var
2332 Window: THelpWindow;
2333Begin
2334 Window := GetActiveWindow;
2335 if Window = nil then
2336 exit;
2337 Window.View.CopySelectionToClipboard;
2338End;
2339
2340Procedure TMainForm.SelectAllPMIOnClick (Sender: TObject);
2341var
2342 Window: THelpWindow;
2343Begin
2344 Window := GetActiveWindow;
2345 if Window = nil then
2346 exit;
2347 Window.View.SelectAll;
2348End;
2349
2350Procedure TMainForm.AddNoteButtonOnClick (Sender: TObject);
2351Begin
2352 AddNote;
2353End;
2354
2355Procedure TMainForm.EnableSearchButton;
2356var
2357 CanSearch: boolean;
2358begin
2359 CanSearch := false;
2360 if CurrentOpenFiles.Count > 0 then
2361 if trim( SearchTextEdit.Text ) > '' then
2362 CanSearch := true;
2363 SearchButton.Enabled := CanSearch;
2364end;
2365
2366Procedure TMainForm.SearchTextEditOnChange (Sender: TObject);
2367Begin
2368 EnableSearchButton;
2369End;
2370
2371Procedure TMainForm.OnHint( Sender: TObject );
2372begin
2373 SetStatus( Application.Hint );
2374end;
2375
2376Procedure TMainForm.DisplaySelectedIndexTopic;
2377var
2378 Topic: TTopic;
2379Begin
2380 if IndexListBox.ItemIndex = -1 then
2381 exit;
2382 Topic := DisplayedIndex.Objects[ IndexListBox.ItemIndex ] as TTopic;
2383 DisplayTopic( Topic );
2384End;
2385
2386Procedure TMainForm.IndexListBoxOnClick (Sender: TObject);
2387Begin
2388 DisplaySelectedIndexTopic;
2389End;
2390
2391Procedure TMainForm.ViewCollapseAllMIOnClick (Sender: TObject);
2392Begin
2393 DisplayContents;
2394 ContentsOutline.CollapseAll;
2395 DisplaySelectedContentsTopic;
2396End;
2397
2398Procedure TMainForm.NotesListBoxOnDblClick (Sender: TObject);
2399Begin
2400 GotoCurrentNote;
2401End;
2402
2403function TMainForm.OwnHelpMode: boolean;
2404var
2405 Filename: string;
2406 NamePart: string;
2407begin
2408 result := false;
2409 if CurrentOpenFiles.Count <> 1 then
2410 exit;
2411
2412 Filename := THelpFile( CurrentOpenFiles[ 0 ] ).Filename;
2413 NamePart := ExtractFileName( Filename );
2414 Result := StrStartsWithIgnoringCase(NamePart, 'newview');
2415end;
2416
2417Procedure TMainForm.HelpMIOnClick (Sender: TObject);
2418Begin
2419 if OwnHelpMode then
2420 begin
2421 DoErrorDlg( NewViewHelpTitle,
2422 AlreadyNewviewHelp );
2423 exit;
2424 end;
2425 Application.HelpContents;
2426End;
2427
2428Procedure TMainForm.NotebookOnPageChanged (Sender: TObject);
2429var
2430 FileIndex: longint;
2431 HelpFile: THelpFile;
2432Begin
2433 EnableControls;
2434 case Notebook.PageIndex of
2435 piContents:
2436 begin
2437 // not really feasible to load contents here, as we rely
2438 // on it for many things
2439 ContentsOutline.Focus;
2440 end;
2441
2442 piIndex:
2443 begin
2444 if not IndexLoaded then
2445 begin
2446 LoadIndex;
2447 end;
2448 IndexSearchEdit.Focus;
2449 end;
2450
2451 piSearch:
2452 begin
2453 SearchButton.Focus;
2454 SearchTextEdit.Focus;
2455 end;
2456
2457 piNotes:
2458 begin
2459 for FileIndex := 0 to CurrentOpenFiles.Count - 1 do
2460 begin
2461 HelpFile := CurrentOpenFiles[ FileIndex ];
2462 if not HelpFile.NotesLoaded then
2463 LoadNotes( HelpFile );
2464 end;
2465 NotesListBox.Focus;
2466 UpdateNotesDisplay;
2467 end;
2468 end;
2469
2470End;
2471
2472Procedure TMainForm.ViewRefreshMIOnClick (Sender: TObject);
2473Begin
2474 RefreshWindows( Windows );
2475End;
2476
2477Procedure TMainForm.ViewNotesMIOnClick (Sender: TObject);
2478Begin
2479 ShowLeftPanel := true;
2480 TabSet.TabIndex := piNotes;
2481End;
2482
2483Procedure TMainForm.ViewSearchMIOnClick (Sender: TObject);
2484Begin
2485 DisplaySearch;
2486End;
2487
2488Procedure TMainForm.ShowTab( TabIndex: longint );
2489Begin
2490 ShowLeftPanel := true;
2491 TabSet.TabIndex := TabIndex;
2492 NotebookOnPageChanged( self );// focus control etc
2493End;
2494
2495Procedure TMainForm.DisplaySearch;
2496Begin
2497 ShowTab( piSearch );
2498End;
2499
2500Procedure TMainForm.ViewIndexMIOnClick (Sender: TObject);
2501Begin
2502 DisplayIndex;
2503End;
2504
2505Procedure TMainForm.DisplayIndex;
2506Begin
2507 ShowTab( piIndex );
2508End;
2509
2510Procedure TMainForm.ViewContentsMIOnClick (Sender: TObject);
2511Begin
2512 DisplayContents;
2513End;
2514
2515Procedure TMainForm.DisplayContents;
2516Begin
2517 ShowTab( piContents );
2518End;
2519
2520function TMainForm.OpenWindow( Topic: TTopic;
2521 Group: longint;
2522 Parent: THelpWindow;
2523 Rect: THelpWindowRect;
2524 FollowAutoLinks: boolean ): THelpWindow;
2525var
2526 Window: THelpWindow;
2527 DisplayTopicRequired: boolean;
2528begin
2529 Window := nil;
2530
2531 if ( Group <> DefaultGroupIndex ) and ( Parent = nil ) then
2532 begin
2533 // Normal window (not a split window) and a specific group is desired.
2534 // So see if we can find one with that group number
2535 Window := FindWindowFromGroup( Group, Windows );
2536
2537 end
2538 else
2539 begin
2540 // only reuse window if it has the same topic.
2541 Window := FindWindowFromTopic( Topic, Windows );
2542 end;
2543
2544 if Window = nil then
2545 begin
2546 DisplayingTopicWindow := true;
2547
2548 // not found, or want a new one
2549 Window := THelpWindow.Create( Parent = nil );
2550
2551 // add to parent
2552 if Parent = nil then
2553 begin
2554 Window.Parent := DisplayPanel;
2555 Windows.Add( Window );
2556 end
2557 else
2558 begin
2559 Window.Parent := Parent.View;
2560 Parent.ChildWindows.Add( Window );
2561 end;
2562
2563 Window.ParentHelpWindow := Parent;
2564
2565 DisplayingTopicWindow := false;
2566
2567 end
2568 else
2569 begin
2570 // reusing an existing window. Don't change parent
2571 end;
2572
2573 Window.Group := Group;
2574
2575 Window.View.PopupMenu := ViewPopupMenu;
2576
2577 Window.View.Images := Window.Images;
2578
2579 Window.View.OnClickLink := OnClickLink;
2580 Window.View.OnOverLink := OnOverLink;
2581 Window.View.OnNotOverLink := OnNotOverLink;
2582
2583 Window.OnClose := OnWindowClose;
2584 Window.OnCloseQuery := OnWindowAboutToClose;
2585 Window.OnDragOver := OnDragOverWindow;
2586 Window.OnDragDrop := OnDragDropToWindow;
2587 Window.OnFontChange := OnWindowFontChange;
2588 Window.OnTab := OnWindowTab;
2589 Window.OnBackTab := OnWindowBackTab;
2590
2591 // Use the contents rect by default...
2592 Topic.GetContentsWindowRect( Window.Rect );
2593 if Rect <> nil then
2594 begin
2595 // the rect is being overridden, so use it instead
2596 if Rect.Left <> -1 then
2597 Window.Rect.Left := Rect.Left;
2598 if Rect.Bottom <> -1 then
2599 Window.Rect.Bottom := Rect.Bottom;
2600 if Rect.Width <> -1 then
2601 Window.Rect.Width := Rect.Width;
2602 if Rect.Height <> -1 then
2603 Window.Rect.Height := Rect.Height;
2604 end;
2605
2606 if Window.ChildWindows.Count > 0 then
2607 begin
2608 // close existing child windows
2609 DestroyListObjects( Window.ChildWindows );
2610 Window.ChildWindows.Clear;
2611 Window.View.Show; // show the view again
2612 end;
2613
2614 DisplayTopicRequired := Window.Topic <> Topic;
2615 Window.Topic := Topic; // set this now so that SetLayout can log meaninful stuff
2616
2617 // Adjust the window size to it's specified Rect
2618 // Must do this before displaying child windows (DisplayTopicInWindow,
2619 // split window autolinks),
2620 // otherwise they will not size themselves correctly
2621 Window.SetLayout;
2622
2623 if DisplayTopicRequired then
2624 begin
2625 DisplayTopicInWindow( Window, FollowAutoLinks, false );
2626 end;
2627
2628 // Bring this window to the front
2629 Window.BringToFront;
2630
2631 Result := Window;
2632end;
2633
2634// Find an existing help window containing the given richtext view control
2635Function TMainForm.FindWindowFromView( View: TRichTextView;
2636 WindowList: TList ): THelpWindow;
2637var
2638 WindowIndex: longint;
2639begin
2640 for WindowIndex:= 0 to WindowList.Count - 1 do
2641 begin
2642 Result:= WindowList[ WindowIndex ];
2643 if Result.View = View then
2644 exit;
2645 Result:= FindWindowFromView( View, Result.ChildWindows );
2646 if Result <> nil then
2647 exit;
2648 end;
2649 Result:= nil;
2650end;
2651
2652// Find an existing help window with the given group number (if any)
2653Function TMainForm.FindWindowFromGroup( Group: longint; WindowList: TList ): THelpWindow;
2654var
2655 WindowIndex: longint;
2656begin
2657 for WindowIndex:= 0 to WindowList.Count - 1 do
2658 begin
2659 Result:= WindowList[ WindowIndex ];
2660 if Result.Group = Group then
2661 exit;
2662 Result:= FindWindowFromGroup( Group, Result.ChildWindows );
2663 if Result <> nil then
2664 exit;
2665 end;
2666 Result:= nil;
2667end;
2668
2669// Find an existing help window alreadying displaying the given topic
2670Function TMainForm.FindWindowFromTopic( Topic: TTopic; WindowList: TList ): THelpWindow;
2671var
2672 WindowIndex: longint;
2673begin
2674 for WindowIndex:= 0 to WindowList.Count - 1 do
2675 begin
2676 Result:= WindowList[ WindowIndex ];
2677 if Result.Topic = Topic then
2678 exit;
2679 Result:= FindWindowFromTopic( Topic, Result.ChildWindows );
2680 if Result <> nil then
2681 exit;
2682 end;
2683 Result:= nil;
2684end;
2685
2686Procedure TMainForm.RefreshFontSubstitutions;
2687var
2688 FileIndex: longint;
2689 HelpFile: THelpFile;
2690begin
2691 for FileIndex := 0 to CurrentOpenFiles.Count - 1 do
2692 begin
2693 HelpFile := CurrentOpenFiles[ FileIndex ];
2694
2695 if Settings.FixedFontSubstitution then
2696 HelpFile.SetupFontSubstitutes( Settings.FixedFontSubstitutes )
2697 else
2698 HelpFile.SetupFontSubstitutes( '' );
2699 end;
2700end;
2701
2702// Redisplay topics in all windows
2703Procedure TMainForm.RefreshWindows( WindowList: TList );
2704var
2705 WindowIndex: longint;
2706 Window: THelpWindow;
2707begin
2708 for WindowIndex:= 0 to WindowList.Count - 1 do
2709 begin
2710 Window:= WindowList[ WindowIndex ];
2711 DisplayTopicInWindow( Window,
2712 false, // don't follow links!
2713 true ); // keep position
2714 RefreshWindows( Window.ChildWindows );
2715 end;
2716end;
2717
2718Procedure TMainForm.WMFollowExternalLink(Var Msg: TMessage);
2719var
2720 tmpFilePath: string;
2721 tmpAltFilePath: string;
2722 tmpIsFileAlreadyOpened: boolean;
2723 tmpHelpFile: THelpFile;
2724 tmpTopic: TTopic;
2725 i: longint;
2726begin
2727 LogEvent(LogDebug, 'tmpFilePath ' + tmpFilePath);
2728
2729 // try in same dir as source file
2730 tmpFilePath := AddDirectorySeparator(ExtractFilePath(g_ExternalLinkSourceFilename)) + g_ExternalLinkFilename;
2731 tmpAltFilePath := tmpFilePath;
2732
2733 // we use paths with extension, because the internal list of helpfiles
2734 // always has extensions inside
2735 if ExtractFileExt(g_ExternalLinkFilename) = '' then
2736 begin
2737 tmpFilePath := ChangeFileExt(tmpFilePath, INF_FILE_EXTENSION);
2738 tmpAltFilePath := ChangeFileExt(tmpFilePath, HELP_FILE_EXTENSION);
2739 end;
2740
2741 // figure out, if the file is already open
2742 tmpIsFileAlreadyOpened := false;
2743 for i := 0 to CurrentOpenFiles.Count - 1 do
2744 begin
2745 tmpHelpFile := CurrentOpenFiles[i];
2746 if StrEndsWithIgnoringCase(tmpHelpFile.Filename, tmpFilePath)
2747 or StrEndsWithIgnoringCase(tmpHelpFile.Filename, tmpAltFilePath) then
2748 begin
2749 tmpIsFileAlreadyOpened := true;
2750 end;
2751 end;
2752
2753 if not tmpIsFileAlreadyOpened then
2754 begin
2755 // different file - try and open it
2756 if not FileExists(tmpFilePath) then
2757 begin
2758 // not in same directory, find in help paths
2759 tmpFilePath := FindHelpFile(g_ExternalLinkFilename);
2760 end;
2761
2762 if not FileExists(tmpFilePath) then
2763 begin
2764 DoErrorDlg('Link Error', 'Cannot find linked file ''' + g_ExternalLinkFilename +'''');
2765 exit;
2766 end;
2767
2768 if g_ExternalLinkKeepCurrent then
2769 begin
2770 if not OpenAdditionalFile(tmpFilePath, false) then
2771 exit;
2772 end
2773 else
2774 begin
2775 if not OpenFile(tmpFilePath, '', false) then
2776 exit;
2777 end;
2778 end;
2779
2780 if g_ExternalLinkTopic = '' then
2781 begin
2782 // specific topic not required.
2783 DisplaySelectedContentsTopic;
2784 exit;
2785 end;
2786
2787 // don't call this search here;
2788 // because we know the file to search in
2789 // otherwise the first occurence of the topic will be
2790 // found
2791 // Topic := FindTopicByGlobalName( g_ExternalLinkTopic );
2792 tmpTopic := nil;
2793 for i := 0 to CurrentOpenFiles.Count - 1 do
2794 begin
2795 tmpHelpFile := CurrentOpenFiles[i];
2796 if StrEndsWithIgnoringCase(tmpHelpFile.Filename, g_ExternalLinkFilename)
2797 or StrEndsWithIgnoringCase(tmpHelpFile.Filename, g_ExternalLinkFilename + INF_FILE_EXTENSION)
2798 or StrEndsWithIgnoringCase(tmpHelpFile.Filename, g_ExternalLinkFilename + HELP_FILE_EXTENSION) then
2799 begin
2800 tmpTopic := tmpHelpFile.FindTopicByGlobalName(g_ExternalLinkTopic);
2801 end;
2802 end;
2803
2804 if tmpTopic = nil then
2805 begin
2806 DoErrorDlg('Link Error', 'Unable to find topic with global name ''' + g_ExternalLinkTopic + '''');
2807 exit;
2808 end;
2809
2810 DisplayTopic(tmpTopic);
2811end;
2812
2813// We are following a link, specified as param1 in msg
2814Procedure TMainForm.WMFollowLink( Var Msg: TMessage );
2815var
2816 NewTopic: TTopic;
2817 Link: THelpLink;
2818 SourceWindow: THelpWindow;
2819begin
2820 Link:= THelpLink( Msg.Param1 );
2821 SourceWindow:= THelpWindow( Msg.Param2 );
2822 NewTopic:= FindTopicForLink( Link );
2823
2824 // remove the link target info from status
2825 SetStatus( '' );
2826
2827 if NewTopic = nil then
2828 begin
2829 // Linked topic not found, this is an error... which kind?
2830
2831 if Link is THelpLinkByResourceID then
2832 begin
2833 // may happen if e.g. PM4.INF is loaded by itself,
2834 // and a link references a resource ID from e.g PM2.INF
2835 DoErrorDlg( InvalidLinkErrorTitle,
2836 InvalidResourceIDLinkErrorA
2837 + IntToStr( THelpLinkByResourceID( Link ).ResourceID )
2838 + InvalidResourceIDLinkErrorB );
2839 end
2840 else
2841 begin
2842 // should never happen, given valid help files
2843 DoErrorDlg( InvalidLinkErrorTitle,
2844 InvalidLinkError );
2845 end;
2846
2847 exit;
2848 end;
2849
2850 UpdateCurrentNavigatePoint;
2851
2852 FollowLink( Link, SourceWindow );
2853
2854 if NewTopic.ShowInContents then
2855 begin
2856 Navigating:= true;
2857 if ContentsOutline.SelectedNode = nil then
2858 ContentsOutline.SetSelectedObject( NewTopic )
2859 else if ContentsOutline.SelectedNode.Data <> NewTopic then
2860 ContentsOutline.SetSelectedObject( NewTopic );
2861 Navigating:= false;
2862 end;
2863 SaveNavigatePoint;
2864 EnableControls;
2865 ShowWindows;
2866
2867end;
2868
2869// Follow the given link from the given window.
2870// ie. open the topic or footnote it points to
2871Procedure TMainForm.FollowLink( Link: THelpLink;
2872 SourceWindow: THelpWindow );
2873var
2874 LinkedTopic: TTopic;
2875 ParentWindow: THelpWindow;
2876 WindowedLink: TWindowedHelpLink;
2877 NewWindow: THelpWIndow;
2878begin
2879 LinkedTopic := FindTopicForLink( Link );
2880
2881 if LinkedTopic = nil then
2882 begin
2883 exit;
2884 end;
2885
2886 if Link is TFootnoteHelpLink then
2887 begin
2888 NewWindow := OpenWindow( LinkedTopic,
2889 DefaultGroupIndex,
2890 nil, // no parent
2891 FootnoteRect,
2892 true );
2893 NewWindow.Caption := TFootnoteHelpLink( Link ).Title;
2894 exit;
2895 end;
2896
2897 WindowedLink := Link as TWindowedHelpLink;
2898
2899 ParentWindow:= nil;
2900 if WindowedLink.Split then
2901 ParentWindow:= SourceWindow;
2902
2903 if WindowedLink.ViewPort then
2904 // link always wants a new window
2905 OpenWindow( LinkedTopic,
2906 DefaultGroupIndex,
2907 ParentWindow,
2908 WindowedLink.Rect,
2909 true )
2910
2911 else if WindowedLink.GroupIndex <> DefaultGroupIndex then
2912 // link overrides group index
2913 OpenWindow( LinkedTopic,
2914 WindowedLink.GroupIndex,
2915 ParentWindow,
2916 WindowedLink.Rect,
2917 true )
2918 else
2919 // no special case
2920 OpenWindow( LinkedTopic,
2921 LinkedTopic.ContentsGroupIndex,
2922 ParentWindow,
2923 WindowedLink.Rect,
2924 true );
2925end;
2926
2927function TMainForm.ShowCodes: boolean;
2928begin
2929 if DebugShowCodesMI = nil then
2930 result := false
2931 else
2932 result := DebugShowCodesMI.Checked;
2933end;
2934
2935function TMainForm.ShowWordIndices: boolean;
2936begin
2937 if DebugShowWordSeparatorsMI = nil then
2938 result := false
2939 else
2940 result := DebugShowWordSeparatorsMI.Checked;
2941end;
2942
2943// Decode and display the topic for the given window.
2944Procedure TMainForm.DisplayTopicInWindow( Window: THelpWindow;
2945 FollowAutoLinks: boolean;
2946 KeepPosition: boolean );
2947var
2948 ImageIndices: TList;
2949 LinkIndex: longint;
2950 Link: THelpLink;
2951 WindowedHelpLink: TWindowedHelpLink;
2952 InternalHelpLink: TInternalHelpLink;
2953 HelpFile: THelpFile;
2954 LinkedTopic: TTopic;
2955 SourceTopic: TTopic;
2956 TopCharIndex: longint;
2957 i: longint;
2958 HighlightWordSequences: TList;
2959 FileIndex: longint;
2960Begin
2961 LogEvent(LogDisplay, 'DisplayTopicInWindow');
2962
2963 SetWaitCursor;
2964
2965 TopCharIndex := Window.View.TopCharIndex;
2966
2967 Window.View.Hide;
2968 Window.View.Clear;
2969 ImageIndices := TList.Create;
2970
2971 HelpFile := TopicFile( Window.Topic );
2972
2973 if ( AllFilesWordSequences.Count > 0 ) // ie we have done a search...
2974 and ViewHighlightSearchWordsMI.Checked then
2975 begin
2976 FileIndex := CurrentOpenFiles.IndexOf( HelpFile );
2977 HighlightWordSequences := AllFilesWordSequences[ FileIndex ];
2978 end
2979 else
2980 begin
2981 HighlightWordSequences := nil;
2982 end;
2983 TopicText.Clear;
2984 Window.Topic.GetText( HighlightWordSequences,
2985 ShowCodes,
2986 ShowWordIndices,
2987 TopicText,
2988 ImageIndices,
2989 Window.Highlights );
2990
2991 HelpFile.GetImages( ImageIndices, Window.Images );
2992
2993 if not HelpFile.NotesLoaded then
2994 LoadNotes( HelpFile );
2995 InsertNotesIntoTopicText( Window.Topic, TopicText );
2996
2997 Window.View.AddText( TopicText.AsPChar );
2998
2999 if KeepPosition then
3000 Window.View.TopCharIndex := TopCharIndex;
3001
3002 Window.View.Show;
3003
3004 if not KeepPosition then
3005 if Window.Highlights.Count > 0 then
3006 // ensure first search match is visible
3007 Window.View.MakeCharVisible( longint( Window.Highlights[ 0 ] ) );
3008
3009 Window.Caption := Window.Topic.Title;
3010 Window.BringToFront;
3011 Window.View.Focus;
3012
3013 // Take a copy of the topic, because the window in question could be changing
3014 // due to recursion!
3015 SourceTopic := Window.Topic;
3016
3017 if FollowAutoLinks then
3018 begin
3019 i := 0;
3020 for LinkIndex:= 0 to SourceTopic.Links.Count - 1 do
3021 begin
3022 Link:= SourceTopic.Links[ LinkIndex ];
3023 if Link is TWindowedHelpLink then
3024 begin
3025 WindowedHelpLink := Link as TWindowedHelpLink;
3026 if WindowedHelpLink.Automatic then
3027 begin
3028 if Link is TInternalHelpLink then
3029 begin
3030 InternalHelpLink := TInternalHelpLink( Link );
3031 LinkedTopic :=
3032 THelpFile( InternalHelpLink.HelpFile ).
3033 Topics[ InternalHelpLink.TopicIndex ];
3034 if LinkedTopic.Index = SourceTopic.Index then
3035 // what the - ? The link wants to open the same topic again
3036 continue;
3037 end;
3038
3039 FollowLink( Link, Window );
3040 Window := Window;
3041
3042 inc( i );
3043 // Note 1: it is possible to crash here if
3044 // e.g. window1 auto-opens window2 which auto-opens window1 with a different topic..
3045 // I can't think of a nice, easy way to detect this
3046 //
3047 // Note 2: If there is no group number specified
3048 // (ie. group = default = 0 ) then behaves as if viewport is set:
3049 // always opens another window.
3050 end;
3051 end;
3052 end;
3053 end;
3054
3055 ClearWaitCursor;
3056
3057 ImageIndices.Destroy;
3058End;
3059
3060Procedure TMainForm.MainFormOnCloseQuery (Sender: TObject;
3061 Var CanClose: Boolean);
3062Begin
3063 LogEvent(LogShutdown, '-------- Shutdown ----------');
3064
3065
3066 if OKToCloseFile then
3067 CloseFile
3068 else
3069 CanClose := false;
3070End;
3071
3072procedure TMainForm.DisplayTopic( Topic: TTopic );
3073begin
3074 if Navigating then
3075 exit;
3076
3077 UpdateCurrentNavigatePoint;
3078
3079 CloseWindows;
3080
3081 CurrentTopic:= Topic;
3082
3083 OpenWindow( CurrentTopic,
3084 CurrentTopic.ContentsGroupIndex,
3085 nil,
3086 nil,
3087 true );
3088 SetStatus( OpenedTopicMsg + IntToStr( Topic.Index ) );
3089
3090 Navigating:= true;
3091
3092 if ContentsOutline.SelectedNode = nil then
3093 ContentsOutline.SetSelectedObject( Topic )
3094 else if ContentsOutline.SelectedNode.Data <> Topic then
3095 ContentsOutline.SetSelectedObject( Topic );
3096
3097 SaveNavigatePoint;
3098
3099 Navigating:= false;
3100 // find in index...
3101 // find in search results...
3102
3103 EnableControls;
3104
3105 ShowWindows;
3106
3107// if Windows.Count > 0 then
3108// THelpWindow( Windows[ 0 ] ).View.Focus;
3109
3110end;
3111
3112// Make the all current help windows visible
3113Procedure TMainForm.ShowWindows;
3114begin
3115 ShowWindowList( Windows );
3116end;
3117
3118// Make the specified windows visible
3119Procedure TMainForm.ShowWindowList( WindowList: TList );
3120var
3121 i: integer;
3122 Window: THelpWindow;
3123begin
3124 for i := 0 to WindowList.Count - 1 do
3125 begin
3126 Window:= WindowList[ i ];
3127 Window.Show;
3128 ShowWindowList( Window.ChildWindows );
3129 end;
3130end;
3131
3132// Global search -----------------------------------------------------------
3133
3134Procedure TMainForm.GlobalSearchMIOnClick (Sender: TObject);
3135begin
3136 DoGlobalSearch( '' );
3137end;
3138
3139Procedure TMainForm.DoGlobalSearch( const SearchText: string );
3140Begin
3141 EnsureGlobalSearchFormLoaded;
3142
3143 GlobalSearchForm.ViewTopicCallback:= OnViewGlobalSearchTopic;
3144 GlobalSearchForm.Show;
3145 WinSetOwner( GlobalSearchForm.Frame.Handle, Frame.Handle );
3146
3147 if SearchText <> '' then
3148 begin
3149 GlobalSearchForm.SearchTextEdit.Text := SearchText;
3150 GlobalSearchForm.DoSearch;
3151 end;
3152End;
3153
3154Procedure TMainForm.OnViewGlobalSearchTopic( FileName: string;
3155 TopicIndex: longint );
3156var
3157 HelpFile: THelpFile;
3158begin
3159 HelpFile:= FindOpenHelpFile( FileName );
3160
3161 if HelpFile = nil then
3162 begin
3163 if OpenFile( Filename, '', false ) then
3164 begin
3165 HelpFile := CurrentOpenFiles[ 0 ];
3166 ClearHelpManager;
3167 end;
3168 end;
3169
3170 if HelpFile <> nil then
3171 if TopicIndex <> -1 then
3172 DisplayTopic( HelpFile.Topics[ TopicIndex ] );
3173
3174end;
3175
3176// Notes -----------------------------------------------------------
3177
3178Procedure TMainForm.GotoNoteButtonOnClick (Sender: TObject);
3179begin
3180 GotoCurrentNote;
3181end;
3182
3183Procedure TMainForm.EditNoteButtonOnClick (Sender: TObject);
3184Begin
3185 if NotesListBox.ItemIndex = -1 then
3186 exit;
3187 EditNote( NotesListBox.ItemIndex );
3188End;
3189
3190Procedure TMainForm.NotesListBoxOnItemFocus (Sender: TObject; Index: LongInt);
3191var
3192 Note: THelpNote;
3193Begin
3194 Note:= NotesListBox.Items.Objects[ NotesListBox.ItemIndex ] as THelpNote;
3195 EnableNotesControls;
3196End;
3197
3198Procedure TMainForm.DeleteNoteButtonOnClick (Sender: TObject);
3199Begin
3200 if NotesListBox.ItemIndex = -1 then
3201 exit;
3202 DeleteNote( NotesListBox.ItemIndex );
3203End;
3204
3205Procedure TMainForm.AddBookmarkMIOnClick (Sender: TObject);
3206Begin
3207 AddBookmark;
3208End;
3209
3210Procedure TMainForm.AddNoteMIOnClick (Sender: TObject);
3211Begin
3212 AddNote;
3213End;
3214
3215// -----------------------------------------------------------
3216
3217Procedure TMainForm.FileCloseMIOnClick (Sender: TObject);
3218Begin
3219 if not OKToCloseFile then
3220 exit;
3221
3222 CloseFile;
3223End;
3224
3225Procedure TMainForm.SetStatus( Text: String );
3226begin
3227 StatusPanel.Caption:= Text;
3228 StatusPanel.Refresh;
3229end;
3230
3231Procedure TMainForm.ResetProgress;
3232begin
3233 ProgressBar.Position:= 0;
3234 ProgressBar.Hide;
3235end;
3236
3237Procedure TMainForm.CoolBarOnSectionResize (HeaderControl: THeaderControl;
3238 section: THeaderSection);
3239Begin
3240
3241End;
3242
3243Procedure TMainForm.CoolBarOnSectionClick (HeaderControl: THeaderControl;
3244 section: THeaderSection);
3245Begin
3246 case Section.Index of
3247 ciOpen:
3248 FileOpen;
3249 ciPrint:
3250 PrintTopics;
3251 ciNavigator:
3252 ShowLeftPanel := not ShowLeftPanel;
3253 ciBack:
3254 NavigateBack;
3255 ciForward:
3256 NavigateForward;
3257 ciAddNote:
3258 AddNote;
3259 ciAddBookmark:
3260 AddBookmark;
3261 ciPrevious:
3262 NavigatePreviousInContents;
3263 ciNext:
3264 NavigateNextInContents;
3265 ciGlobalSearch:
3266 DoGlobalSearch( '' );
3267 end;
3268
3269End;
3270
3271// ---------------- Notes ----------------------
3272
3273function TMainForm.FindOriginalNoteCharIndex( NoteCharIndex: longword;
3274 Topic: TTopic ): longword;
3275var
3276 NoteIndex: longint;
3277 Note: THelpNote;
3278begin
3279 Result := NoteCharIndex;
3280 for NoteIndex := 0 to Notes.Count - 1 do
3281 begin
3282 Note := Notes[ NoteIndex ];
3283 if Note.Topic = Topic then
3284 if Note.InsertPoint < NoteCharIndex then
3285 dec( Result, Note.InsertText.Length );
3286 end;
3287end;
3288
3289function TMainForm.FindActualNoteCharIndex( NoteCharIndex: longword;
3290 MaxNoteIndex: longword;
3291 Topic: TTopic ): longword;
3292var
3293 NoteIndex: longint;
3294 Note: THelpNote;
3295begin
3296 NoteIndex:= 0;
3297 Result:= NoteCharIndex;
3298 for NoteIndex:= 0 to MaxNoteIndex - 1 do
3299 begin
3300 Note:= Notes[ NoteIndex ];
3301 if Note.Topic = Topic then
3302 if Note.InsertPoint < NoteCharIndex then
3303 inc( Result, Note.InsertText.Length );
3304 end;
3305end;
3306
3307procedure TMainForm.RefreshNoteInsertInfo( NoteIndex: longword );
3308var
3309 Note: THelpNote;
3310begin
3311 Note:= Notes[ NoteIndex ];
3312
3313 if Note.Topic = nil then
3314 exit;
3315 with Note do
3316 begin
3317 InsertText.AssignString( '<color #'
3318 + IntToHex( Settings.Colors[ NotesTextColorIndex ], 6 )
3319 + '><link note'
3320 + IntToStr( NoteIndex )
3321 + '>' );
3322 InsertText.Add( Text );
3323 InsertText.AddString( '</color></link>' );
3324 end;
3325end;
3326
3327procedure TMainForm.ClearNotes;
3328begin
3329 DestroyListObjects( Notes );
3330 Notes.Clear;
3331end;
3332
3333procedure TMainForm.AddNote;
3334var
3335 Note: THelpNote;
3336 Window: THelpWindow;
3337begin
3338 Window := GetActiveWindow;
3339 if Window = nil then
3340 begin
3341 DoErrorDlg( AddNoteTitle,
3342 AddNoteCursorError );
3343 exit;
3344 end;
3345
3346 if Window.View.CursorIndex = -1 then
3347 begin
3348 DoErrorDlg( AddNoteTitle,
3349 AddNoteCursorError );
3350 exit;
3351 end;
3352
3353 // check that the note position isn't
3354 // within a note already
3355 if Window.View.LinkFromIndex( Window.View.CursorIndex ) <> '' then
3356 begin
3357 DoErrorDlg( AddNoteTitle,
3358 NoteWithinNoteError );
3359 exit;
3360 end;
3361
3362 // ask for note text
3363 NoteForm.DeleteNoteButton.Enabled := false; // can't delete it while creating!
3364 NoteForm.Text.Clear;
3365 if NoteForm.ShowModal <> mrOK then
3366 exit;
3367
3368 // store note data
3369 Note := THelpNote.Create;
3370 Note.Text.Assign( NoteForm.Text );
3371
3372 // compensate for existing notes
3373 if Window.View.CursorIndex <> -1 then
3374 Note.InsertPoint := FindOriginalNoteCharIndex( Window.View.CursorIndex, Window.Topic )
3375 else
3376 Note.InsertPoint := 0;
3377
3378 Note.Topic := Window.Topic;
3379
3380 Notes.Add( Note );
3381
3382 // redisplay topic
3383 DisplayTopicInWindow( Window,
3384 false, // don't follow links!
3385 true ); // keep position
3386 Window.View.SelectionStart := FindActualNoteCharIndex( Note.InsertPoint,
3387 Notes.Count - 1,
3388 Window.Topic );
3389 UpdateNotesDisplay;
3390
3391 SaveNotes;
3392
3393end;
3394
3395procedure TMainForm.DeleteNote( NoteIndex: longint );
3396var
3397 Note: THelpNote;
3398begin
3399 Note := Notes[ NoteIndex ];
3400 Notes.Delete( NoteIndex );
3401
3402 RefreshWindows( Windows );
3403
3404 Note.Destroy;
3405
3406 UpdateNotesDisplay;
3407
3408 SaveNotes;
3409end;
3410
3411Procedure TMainForm.EditNote( NoteIndex: longint );
3412var
3413 Note: THelpNote;
3414begin
3415 Note:= Notes[ NoteIndex ];
3416
3417 NoteForm.Text.Assign( Note.Text );
3418
3419 NoteForm.DeleteNoteButton.Enabled:= true;
3420
3421 if NoteForm.ShowModal = mrCancel then
3422 exit;
3423
3424 if NoteForm.ModalResult = cmDiscard then
3425 begin
3426 DeleteNote( NoteIndex );
3427 exit;
3428 end;
3429
3430 Note.Text.Assign( NoteForm.Text );
3431
3432 RefreshWindows( Windows );
3433
3434 UpdateNotesDisplay;
3435
3436 SaveNotes;
3437end;
3438
3439Procedure TMainForm.GotoCurrentNote;
3440var
3441 Note: THelpNote;
3442Begin
3443 if NotesListBox.ItemIndex = -1 then
3444 exit;
3445 Note:= NotesListBox.Items.Objects[ NotesListBox.ItemIndex ] as THelpNote;
3446 DisplayTopic( Note.Topic );
3447End;
3448
3449// ---------------- Bookmarks ----------------------
3450
3451procedure TMainForm.OnBookmarksChanged( Sender: TObject );
3452begin
3453 BuildBookmarksMenu;
3454 UpdateBookmarksForm;
3455 SaveBookmarks;
3456end;
3457
3458procedure TMainForm.AddBookmark;
3459var
3460 Bookmark: TBookmark;
3461begin
3462 if Windows.Count = 0 then
3463 exit;
3464
3465 Bookmark := TBookmark.Create;
3466 SaveWindows( Windows, Bookmark.Windows, nil );
3467
3468 if ContentsOutline.SelectedNode <> nil then
3469 begin
3470 Bookmark.ContentsTopic:=
3471 ContentsOutline.SelectedNode.Data as TTopic;
3472 Bookmark.Name := Bookmark.ContentsTopic.Title;
3473 end
3474 else
3475 begin
3476 Bookmark.ContentsTopic:= nil;
3477 // Bookmark.Name := THelpWindow( Windows[ 0 ] ).Title;
3478 end;
3479
3480 Bookmarks.Add( Bookmark );
3481 OnBookmarksChanged( self );
3482end;
3483
3484Procedure TMainForm.BookmarksMenuItemClick( Sender: TObject );
3485var
3486 Tag: longint;
3487 MenuItem: TMenuItem;
3488 Bookmark: TBookmark;
3489begin
3490 MenuItem:= Sender as TMenuItem;
3491 Tag:= MenuItem.Tag;
3492 Bookmark := Bookmarks[ Tag ];
3493
3494 NavigateToBookmark( Bookmark );
3495end;
3496
3497Procedure TMainForm.NavigateToBookmark( Bookmark: TBookmark );
3498Begin
3499 UpdateCurrentNavigatePoint;
3500 NavigateToPoint( Bookmark );
3501 SaveNavigatePoint;
3502End;
3503
3504Procedure TMainForm.BuildBookmarksMenu;
3505var
3506 i: integer;
3507 Bookmark: TBookmark;
3508 MenuItem: TMenuItem;
3509begin
3510 DestroyListObjects( BookmarksMenuItems );
3511 BookmarksMenuItems.Clear;
3512
3513 if Bookmarks.Count > 0 then
3514 begin
3515 MenuItem:= TMenuItem.Create( self );
3516 MenuItem.Caption:= '-';
3517 BookmarksMenu.Add( MenuItem );
3518 BookmarksMenuItems.Add( MenuItem );
3519 end;
3520
3521 for i:= 0 to Bookmarks.Count -1 do
3522 begin
3523 Bookmark := Bookmarks[ i ];
3524 MenuItem:= TMenuItem.Create( self );
3525
3526 MenuItem.Caption:= Bookmark.Name;
3527 MenuItem.OnClick:= BookmarksMenuItemClick;
3528 MenuItem.Tag:= i;
3529 BookmarksMenu.Add( MenuItem );
3530 BookmarksMenuItems.Add( MenuItem );
3531 end;
3532end;
3533
3534Procedure TMainForm.UpdateBookmarksForm;
3535begin
3536 if Assigned( BookmarksForm ) then
3537 BookmarksForm.RefreshList;
3538end;
3539
3540Procedure TMainForm.ClearBookmarks;
3541begin
3542 ClearListAndObjects( Bookmarks );
3543 BuildBookmarksMenu;
3544 if Assigned( BookmarksForm ) then
3545 begin
3546 UpdateBookmarksForm; // clear bookmarks for next show
3547 BookmarksForm.Hide;
3548 end;
3549
3550end;
3551
3552procedure TMainForm.LoadBookmarks( HelpFile: THelpFile );
3553var
3554 Bookmark: TBookmark;
3555 BookmarksFile: TextFile;
3556 BookmarksFileName: string;
3557 S: string;
3558begin
3559 LogEvent(LogSettings, 'Load bookmarks for ' + HelpFile.Filename);
3560
3561 BookmarksFileName:= ChangeFileExt( HelpFile.FileName, '.bmk' );
3562
3563 if not FileExists( BookmarksFileName ) then
3564 exit;
3565
3566 FileMode := fmInput;
3567 AssignFile( BookmarksFile, BookmarksFileName );
3568 try
3569 Reset( BookmarksFile );
3570 try
3571 while not Eof( BookmarksFile ) do
3572 begin
3573 ReadLn( BookmarksFile, s );
3574 if trim( Uppercase( s ) ) = '[BOOKMARK]' then
3575 begin
3576 Bookmark:= TBookmark.Load( BookmarksFile, HelpFile );
3577 Bookmarks.Add( Bookmark );
3578 end;
3579 end;
3580 finally
3581 System.Close( BookmarksFile );
3582 end;
3583 except
3584 on e: exception do
3585 DoErrorDlg( LoadBookmarksTitle,
3586 LoadBookmarksError
3587 + e.message );
3588 end;
3589end;
3590
3591procedure TMainForm.SaveBookmarks;
3592var
3593 FileIndex: integer;
3594 HelpFile: THelpFile;
3595begin
3596 for FileIndex := 0 to CurrentOpenFiles.Count - 1 do
3597 begin
3598 HelpFile := CurrentOpenFiles[ FileIndex ];
3599 SaveBookmarksForFile( HelpFile );
3600 end;
3601end;
3602
3603procedure TMainForm.SaveNotes;
3604var
3605 FileIndex: integer;
3606 HelpFile: THelpFile;
3607begin
3608 LogEvent(LogSettings, 'Save notes');
3609
3610 for FileIndex := 0 to CurrentOpenFiles.Count - 1 do
3611 begin
3612 HelpFile := CurrentOpenFiles[ FileIndex ];
3613 SaveNotesForFile( HelpFile );
3614 end;
3615end;
3616
3617procedure TMainForm.SaveBookmarksForFile( HelpFile: THelpFile );
3618var
3619 i: integer;
3620 Bookmark: TBookmark;
3621 BookmarksFile: TextFile;
3622 BookmarksFileName: string;
3623 BookmarkCount: integer;
3624begin
3625 LogEvent(LogSettings, 'Save bookmarks for ' + HelpFile.Filename);
3626
3627 BookmarksFileName:= ChangeFileExt( HelpFile.FileName, '.bmk' );
3628
3629 BookmarkCount:= 0;
3630 for i:= 0 to Bookmarks.Count - 1 do
3631 begin
3632 Bookmark := Bookmarks[ i ];
3633
3634 if Bookmark.ContentsTopic.HelpFile = HelpFile then
3635 inc( BookmarkCount );
3636 end;
3637
3638 if BookmarkCount = 0 then
3639 begin
3640 if FileExists( BookmarksFileName ) then
3641 DeleteFile( BookmarksFileName );
3642 exit;
3643 end;
3644
3645 AssignFile( BookmarksFile, BookmarksFileName );
3646 try
3647 Rewrite( BookmarksFile );
3648 try
3649 for i := 0 to Bookmarks.Count - 1 do
3650 begin
3651 Bookmark:= Bookmarks[ i ];
3652 if Bookmark.ContentsTopic.HelpFile = HelpFile then
3653 begin
3654 WriteLn( BookmarksFile, '[Bookmark]' );
3655 Bookmark.Save( BookmarksFile );
3656 end;
3657 end;
3658 finally
3659 System.Close( BookmarksFile );
3660 end;
3661 except
3662 on e: exception do
3663 DoErrorDlg( SaveBookmarksTitle,
3664 SaveBookmarksError
3665 + e.message );
3666 end;
3667end;
3668
3669// Reads colors back from controls, in case they have changed by
3670// drag and drop
3671Procedure TMainForm.GetColors;
3672begin
3673 with Settings do
3674 begin
3675 Colors[ ContentsBackgroundColorIndex ] := ContentsOutline.Color;
3676 Colors[ ContentsTextColorIndex ] := ContentsOutline.PenColor;
3677 Colors[ IndexBackgroundColorIndex ] := IndexListBox.Color;
3678 Colors[ IndexTextColorIndex ] := IndexListBox.PenColor;
3679 Colors[ SearchBackgroundColorIndex ] := SearchResultsListBox.Color;
3680 Colors[ SearchTextColorIndex ] := SearchResultsListBox.PenColor;
3681 Colors[ NotesListBackgroundColorIndex ] := NotesListBox.Color;
3682 Colors[ NotesListTextColorIndex ] := NotesListBox.PenColor;
3683 end;
3684end;
3685
3686Procedure TMainForm.MainFormOnDestroy (Sender: TObject);
3687Begin
3688 LogEvent(LogShutdown, 'MainFormOnDestroy');
3689
3690 LogEvent(LogSettings, 'Write window position');
3691 WriteWindowPos( self );
3692
3693 LogEvent(LogSettings, 'Update colors');
3694 GetColors;
3695
3696 LogEvent(LogSettings, 'Save settings');
3697 SaveSettings;
3698 LogEvent(LogSettings, 'Save settings done');
3699
3700 // else- don't save position/size if doing own help
3701
3702 TopicText.Destroy;
3703
3704 LogEvent(LogShutdown, 'Destroy MRU menu items');
3705 MRUMenuItems.Destroy;
3706
3707 LogEvent(LogShutdown, 'Destroy navigate to menu items');
3708 NavigateToMenuItems.Destroy;
3709
3710 LogEvent(LogShutdown, 'Destroy pagehistory');
3711 PageHistory.Destroy;
3712
3713 LogEvent(LogShutdown, 'Clear/destroy notes');
3714 ClearNotes;
3715 Notes.Destroy;
3716
3717 LogEvent(LogShutdown, 'Clear/destroy bookmarks');
3718 ClearBookmarks;
3719 Bookmarks.Destroy;
3720
3721 LogEvent(LogShutdown, 'Destroy bookmark menu items');
3722 BookmarksMenuItems.Destroy;
3723
3724 LogEvent(LogShutdown, 'Destroy files/index/windows');
3725 CurrentOpenFiles.Destroy;
3726 DisplayedIndex.Destroy;
3727 Windows.Destroy;
3728
3729 // tell help manager(s) we are stopping.
3730 PostHelpManagerMessage( NHM_FORGET_VIEWER, 0, 0 );
3731
3732 HelpManagerWindows.Destroy;
3733
3734 DestroyListObjects( Settings.MRUList );
3735 Settings.MRUList.Destroy;
3736
3737 // [20231023 ALT] Restore any previous system-modal window state
3738 if g_LastSysModalWindow <> NULLHANDLE then
3739 begin
3740 WinSetSysModalWindow( HWND_DESKTOP, g_LastSysModalWindow );
3741 end;
3742
3743 // TODO rbri maybe we have to do this
3744 // Parameters.FilenamesParam.Destroy;
3745
3746 if g_CurrentLanguageFile <> nil then
3747 g_CurrentLanguageFile.Destroy;
3748
3749 LogEvent(LogShutdown, 'Close global filelist');
3750 GlobalFilelist.Destroy;
3751
3752 LogEvent(LogShutdown, 'Close shared memory');
3753 SharedMemory.Destroy;
3754
3755 AllFilesWordSequences.Destroy;
3756
3757 LogEvent(LogShutdown, 'MainFormOnDestroy done');
3758End;
3759
3760Procedure TMainForm.MainFormOnSetupShow (Sender: TObject);
3761Begin
3762 LogEvent(LogSettings, 'OnSetupShow');
3763 TabSet.TabIndex := 0;
3764 Notebook.PageIndex := 0;
3765End;
3766
3767Procedure TMainForm.OnException( Sender: TObject;
3768 E: Exception );
3769var
3770 TheText : string;
3771 F: TextFile;
3772 i: integer;
3773 HelpFile: THelpFile;
3774 LogFilename: string;
3775
3776begin
3777 LogFilename := GetLogFilesDir + CrashLogFileName;
3778
3779 LogException( E,
3780 LogFileName,
3781 'NewView',
3782 GetAppVersion,
3783 F );
3784
3785 if CurrentOpenFiles <> nil then
3786 begin
3787 WriteLn( F, 'Loaded files ('
3788 + IntToStr( CurrentOpenFiles.Count )
3789 + '):' );
3790 try
3791 for i := 0 to CurrentOpenFiles.Count - 1 do
3792 begin
3793 HelpFile := CurrentOpenFiles[ i ];
3794 WriteLn( F, HelpFile.Filename );
3795 end;
3796 except
3797 end;
3798 end;
3799 try
3800 if CurrentTopic <> nil then
3801 WriteLn( F, 'Last major topic index: '
3802 + IntToStr( CurrentTopic.Index ) );
3803 except
3804 // ignore exceptions if there isn't a valid current topic
3805 end;
3806 if Windows <> nil then
3807 begin
3808 WriteLn( F, 'Top-level open windows: '
3809 + IntToStr( Windows.Count ) );
3810 end;
3811
3812 System.Close( F );
3813
3814 TheText := ApplicationErrorA + StrCRLF
3815 + StrCRLF
3816 + E.Message + StrCRLF
3817 + ApplicationErrorB
3818 + LogFilename
3819 + ')' + StrCRLF
3820 + StrCRLF
3821 + ApplicationErrorC
3822 + StrCRLF;
3823
3824 if DoYesNoDlg( ApplicationErrorTitle,
3825 TheText ) then
3826 begin
3827 // exit a bit more nicely - remove ourselves from the global filelist.
3828 GlobalFilelist.RemoveWindowFiles( Frame.Handle );
3829 Application.Terminate;
3830 end;
3831end;
3832
3833// give our main window a unique class name we can find
3834procedure TMainForm.GetClassData(var ClassData: TClassData);
3835Begin
3836 inherited GetClassData( ClassData );
3837 ClassData.ClassName := MAIN_WINDOW_CLASS_NAME;
3838End;
3839
3840// Position the window offset from existing top help window (if any)
3841Procedure TMainForm.PositionWindow;
3842var
3843 hTopWindow: HWND;
3844 TopHelpWindowPos: SWP;
3845 Offset: longint;
3846Begin
3847 hTopWindow := FindTopFormWindow( MAIN_WINDOW_CLASS_NAME );
3848
3849 if hTopWindow <> NULLHANDLE then
3850 begin
3851
3852 // we will offset new window by height of title bar + border
3853 Offset := Screen.SystemMetrics( smCyTitleBar )
3854 + Screen.SystemMetrics( smCySizeBorder );
3855
3856 // found an existing help window, find its position...
3857 if WinQueryWindowPos( hTopWindow,TopHelpWindowPos ) then
3858 begin
3859 // [ALT 2023-10-24] ...but only if it's fully on the screen
3860 if ( TopHelpWindowPos.X >= 0 ) and
3861 ( TopHelpWindowPos.X + Width + Offset <= Screen.Width ) and
3862 ( TopHelpWindowPos.Y >= Offset ) and
3863 ( TopHelpWindowPos.Y + Height + Offset <= Screen.Height )
3864 then
3865 Begin
3866 if ( TopHelpWindowPos.FL and ( SWP_MINIMIZE or SWP_MINIMIZE ) ) > 0 then
3867 Begin
3868 // window is maximized or minimised, so get the restore position from window USHORTs
3869 TopHelpWindowPos.x := WinQueryWindowUShort( hTopWindow, QWS_XRESTORE );
3870 TopHelpWindowPos.Y := WinQueryWindowUShort( hTopWindow, QWS_YRESTORE );
3871 end;
3872
3873 Left := TopHelpWindowPos.x;
3874 Bottom := TopHelpWindowPos.y;
3875 end;
3876
3877 // got the reference position, now apply the offset (but staying on screen)
3878 if Left + Width + Offset <= Screen.Width then
3879 Left := Left + Offset;
3880 Bottom := Max( 0, Bottom - Offset );
3881
3882 // I guess I am leaving width/height out for compatibility...?
3883 end;
3884 end;
3885end;
3886
3887Procedure TMainForm.OnHelp( context: THelpContext;
3888 var Result: Boolean );
3889begin
3890 if OwnHelpMode then
3891 begin
3892 // we are viewing the help file now - display our own help!
3893 PostMsg( Handle, NHM_TOPIC_BY_RESOURCE_ID, context, 0 );
3894 exit;
3895 end;
3896
3897 Application.HelpContext( context );
3898end;
3899
3900Procedure TMainForm.MainFormOnCreate (Sender: TObject);
3901var
3902 tmpCmdLine: AnsiString;
3903Begin
3904 LogEvent(LogStartup, 'MainFormOnCreate');
3905
3906 StartingUp := true;
3907
3908 SharedMemory := AccessSharedMemory;
3909 GlobalFilelist := TGlobalFilelist.Create;
3910
3911 // parse parameters into Parameters object
3912 tmpCmdLine := nativeOS2GetCmdLineParameter;
3913 CmdLineParameters := TCmdLineParameters.Create;
3914 CmdLineParameters.parseCmdLine(tmpCmdLine);
3915
3916 Application.HelpFile := CmdLineParameters.GetOwnHelpFilename; // OWN_HELP_MARKER;
3917 Application.OnHelp := OnHelp;
3918
3919 RegisterForLanguages( OnLanguageEvent );
3920
3921 // if debug is not enabled, get rid of the debug menu and separator.
3922 if not CmdLineParameters.isDebugEnabled then
3923 begin
3924 ToolsDebugSep.Destroy;
3925 ToolsDebugMenu.Destroy;
3926 DebugShowCodesMI := nil;
3927 DebugShowWordSeparatorsMI := nil;
3928 end;
3929
3930 // set up globals for Exec
3931 ExecViaSession := true;
3932 AsynchExec := true;
3933
3934 // set up form icons
3935 Forms.FormIconResourceID := 1;
3936
3937 Application.OnException := OnException;
3938
3939 ContentsOutline.SmoothScroll := false;
3940
3941 LogEvent(LogStartup, 'Choosing default font: Trying Window Text setting');
3942
3943 Font := GetNiceDefaultFont;
3944
3945 // Set the menu fonts, because they remember their own specific one
3946 MainMenu.Font := Screen.MenuFont;
3947 ViewPopupMenu.Font := Screen.MenuFont;
3948
3949 // NOTE: SPCC will copy this font to TApplication
3950 // in TApplication.Run
3951
3952 LogEvent(LogStartup, 'Starting NewView: MainFormOnCreate');
3953
3954 g_LastSysModalWindow := NULLHANDLE;
3955
3956 Application.OnHint := OnHint;
3957
3958 StartMem := MemAvailBytes;
3959
3960 DisplayedIndex := TStringList.Create;
3961
3962 HelpManagerWindows := TList.Create;
3963
3964 AllFilesWordSequences := TList.Create;
3965
3966 CurrentOpenFiles := TList.Create;
3967 Notes := TList.Create;
3968 Bookmarks := TList.Create;
3969 BookmarksMenuItems := TList.Create;
3970 Windows := TList.Create;
3971
3972 TopicText := TAString.Create;
3973
3974 Navigating := false;
3975 InIndexSearch := false;
3976 SettingFont := false;
3977
3978 PageHistory := TStringList.Create;
3979 CurrentHistoryIndex := -1;
3980
3981 Settings.MRUList := TList.Create;
3982
3983 MRUMenuItems := TList.Create;
3984 NavigateToMenuItems := TList.Create;
3985
3986 LogEvent(LogSettings, 'Loading settings');
3987
3988 LoadSettings;
3989 SetShowLeftPanel( ShowLeftPanel ); // update menu
3990
3991 // load default strings
3992 LogEvent(LogSettings, 'Loading language');
3993
3994 // the user likes to have english
3995 // the normal automatic will fall back to
3996 // the environment setting but in the special
3997 // case we have to start the default
3998 if CmdLineParameters.getLanguage = 'en' then
3999 begin
4000 LoadLanguage('');
4001 end
4002 else
4003 begin
4004 if CmdLineParameters.getLanguage <> '' then
4005 begin
4006 if not LoadAutoLanguage('newview', CmdLineParameters.getLanguage) then
4007 begin
4008 LoadDefaultLanguage('newview');
4009 end
4010 end
4011 else
4012 begin
4013 LoadDefaultLanguage('newview');
4014 end;
4015 end;
4016
4017 LogEvent(LogSettings, 'Applying settings');
4018 ApplySettings;
4019
4020 // default position is centered..
4021 LogEvent(LogSettings, 'Set default position');
4022 if Width > Screen.Width then
4023 Width := Screen.Width;
4024 if Height > Screen.Height then
4025 Height := Screen.Height;
4026 Left := ( Screen.Width - Width ) div 2;
4027 Bottom := ( Screen.Height - Height ) div 2;
4028
4029 LogEvent(LogSettings, 'ReadWindowPos');
4030 ReadWindowPos( Self );
4031
4032 PositionWindow;
4033
4034 LogEvent(LogSettings, 'Creating MRU list');
4035
4036 CreateMRUMenuItems;
4037
4038 CloseFile;
4039
4040 LogEvent(LogStartup, 'OnCreate done');
4041
4042 if CmdLineParameters.getWindowPositionFlag then
4043 begin
4044 SmartSetWindowPos( self,
4045 CmdLineParameters.getWindowPosition.Left,
4046 CmdLineParameters.getWindowPosition.Bottom,
4047 CmdLineParameters.getWindowPosition.Width,
4048 CmdLineParameters.getWindowPosition.Height,
4049 false );
4050 end;
4051
4052 LogEvent(LogStartup, 'MainFormOnCreate Done');
4053End;
4054
4055Procedure TMainForm.ApplySettings;
4056var
4057 ToolbarBitmap: TBitmap;
4058begin
4059 ContentsOutline.Color:= Settings.Colors[ ContentsBackgroundColorIndex ];
4060 ContentsOutline.PenColor:= Settings.Colors[ ContentsTextColorIndex ];
4061 ContentsOutline.TreeLineColor:= Settings.Colors[ ContentsLinesColorIndex ];
4062 IndexListBox.Color:= Settings.Colors[ IndexBackgroundColorIndex ];
4063 IndexListBox.PenColor:= Settings.Colors[ IndexTextColorIndex ];
4064 SearchResultsListBox.Color:= Settings.Colors[ SearchBackgroundColorIndex ];
4065 SearchResultsListBox.PenColor:= Settings.Colors[ SearchTextColorIndex ];
4066 NotesListBox.Color:= Settings.Colors[ NotesListBackgroundColorIndex ];
4067 NotesListBox.PenColor:= Settings.Colors[ NotesListTextColorIndex ];
4068
4069 SettingFont := true;
4070 Notebook.ParentFont := true;
4071 ContentsOutline.ParentFont := true;
4072 IndexListBox.ParentFont := true;
4073 SearchResultsListBox.ParentFont := true;
4074 NotesListBox.ParentFont := true;
4075 TabSet.ParentFont := true;
4076 Coolbar.ParentFont := true;
4077 if Settings.Fonts[ ApplicationFontIndex ] <> nil then
4078 Font := Settings.Fonts[ ApplicationFontIndex ]
4079 else
4080 Font := GetNiceDefaultFont;
4081 SettingFont := false;
4082
4083 Coolbar.BackgroundBitmap := nil;
4084 if FileExists( Settings.ToolbarBackgroundImageFilename ) then
4085 begin
4086 ToolbarBitmap:= TBitmap.Create;
4087 try
4088 ToolbarBitmap.LoadFromFIle( Settings.ToolbarBackgroundImageFilename );
4089 Coolbar.BackgroundBitmap := ToolbarBitmap;
4090 except
4091 end;
4092 ToolbarBitmap.Destroy;
4093 end;
4094
4095 CoolBar.ShowImages := Settings.ToolbarStyle in [ tsImages, tsImagesAndText ];
4096 CoolBar.ShowText := Settings.ToolbarStyle in [ tsText, tsImagesAndText ];
4097
4098 CoolBar.SetMinConstButtonWidth;
4099
4100 DisplayPanel.Color := Settings.Colors[ TopicBackgroundColorIndex ];
4101
4102 SetupViews( Windows );
4103end;
4104
4105// Setup the rich text views in the specified windows (e.g for changing global settings)
4106Procedure TMainForm.SetupViews( WindowList: TList );
4107var
4108 WindowIndex: longint;
4109 Window: THelpWindow;
4110begin
4111 for WindowIndex := 0 to WindowList.Count - 1 do
4112 begin
4113 Window := WindowList[ WindowIndex ];
4114 Window.SetupRTView;
4115 SetupViews( Window.ChildWindows );
4116 end;
4117end;
4118
4119Procedure TMainForm.PostHelpManagerMessage( MessageType: ULONG;
4120 Param1: long;
4121 Param2: long );
4122var
4123 i: longint;
4124begin
4125 for i := 0 to HelpManagerWindows.Count - 1 do
4126 PostMsg( HWND( HelpManagerWindows[ i ] ),
4127 MessageType,
4128 Param1,
4129 Param2 );
4130end;
4131
4132Procedure TMainForm.ClearHelpManager;
4133Begin
4134 if not CmdLineParameters.getHelpManagerFlag then
4135 exit;
4136
4137 // tell the help manager(s) we are no longer playing with them
4138 PostHelpManagerMessage( NHM_FORGET_VIEWER, 0, 0 );
4139
4140 CmdLineParameters.setHelpManagerFlag(false);
4141
4142 HelpManagerWindows.Clear;
4143End;
4144
4145Procedure TMainForm.MainFormOnShow (Sender: TObject);
4146Begin
4147 EnableCallstackLogging( true );
4148
4149 LogEvent(LogStartup, 'MainFormOnShow');
4150
4151 if CmdLineParameters.getOwnerWindow <> NULLHANDLE then
4152 begin
4153 LogEvent(LogStartup, 'Setting owner: '
4154 + IntToStr( CmdLineParameters.getOwnerWindow));
4155 WinSetOwner( Frame.Handle,
4156 CmdLineParameters.getOwnerWindow );
4157 end;
4158
4159 if CmdLineParameters.getHelpManagerFlag then
4160 begin
4161 LogEvent(LogStartup, ' Help Manager Title: '
4162 + StrPasWithLength( pSharedStruct ^. Title,
4163 SHARED_STRUCT_TITLE_SIZE ) );
4164 HelpManagerVersion := StrPasWithLength( pSharedStruct ^. Version,
4165 SHARED_STRUCT_VERSION_SIZE );
4166 LogEvent(LogStartup, ' Help Manager Version: ' + HelpManagerVersion );
4167
4168 end;
4169
4170 CoolBar.SetMinConstButtonWidth;
4171
4172 LogEvent(LogStartup, 'Post WM_OPENED');
4173
4174 ResetProgress;
4175
4176 AddShortcut( kbF11, kbF11 ); // prev in contents
4177 AddShortcut( kbF12, kbF12 ); // next in contents
4178 AddShortcut( kbF7, kbF7 ); // back
4179 AddShortcut( kbF8, kbF8 ); // forward
4180 AddShortcut( kbCtrlCLeft, kbCtrlCLeft ); // back
4181
4182 PostMsg( Handle, WM_OPENED, 0, 0 );
4183End;
4184
4185Procedure TMainForm.DisplaySelectedContentsTopic;
4186var
4187 Topic: TTopic;
4188Begin
4189 if ContentsOutline.SelectedNode = nil then
4190 exit;
4191 Topic := ContentsOutline.SelectedNode.Data as TTopic;
4192 DisplayTopic( Topic );
4193End;
4194
4195// Check that the HELP and BOOKSHELF environment variables
4196// are defined (as they should be on any working OS/2 system).
4197// Show a warning message if not.
4198Procedure TMainForm.CheckEnvironmentVars;
4199var
4200 HelpOK: boolean;
4201 BookshelfOK: boolean;
4202 ErrorText: string;
4203begin
4204 HelpOK := GetEnv( HelpPathEnvironmentVar ) <> '';
4205 BookshelfOK := GetEnv( BookshelfEnvironmentVar ) <> '';
4206 if HelpOK and BookshelfOK then
4207 // all ok.
4208 exit;
4209
4210 // One or both missing
4211
4212 ErrorText := '';
4213 if not BookshelfOK then
4214 ErrorText := ErrorText
4215 + EnvironmentVarUndefined
4216 + BookshelfEnvironmentVar
4217 + StrCRLF;
4218
4219 if not HelpOK then
4220 ErrorText := ErrorText
4221 + EnvironmentVarUndefined
4222 + HelpPathEnvironmentVar
4223 + StrCRLF;
4224
4225 DoWarningDlg( EnvironmentVarErrorTitle,
4226 EnvironmentVarError
4227 + StrCRLF
4228 + StrCRLF
4229 + ErrorText );
4230
4231end;
4232
4233Procedure LoadSupportDLL;
4234begin
4235 try
4236 LoadDLLFunction( 'newview.dll',
4237 'LZWDECOMPRESSBLOCK',
4238 hNewViewDLL,
4239 pointer( LZWDecompressBlock ) );
4240 except
4241 on E: Exception do
4242 begin
4243 DoErrorDlg( 'DLL Error',
4244 E.Message );
4245 LZWDecompressBlock := nil;
4246 end;
4247 end;
4248end;
4249
4250Procedure TMainForm.WMOpened( Var Msg: TMessage );
4251var
4252 Filenames: TStringList;
4253 M1: longword;
4254 OpenFirstTopic: boolean;
4255begin
4256 if Application.HelpFile = '' then
4257 DoErrorDlg( 'NewView Help', 'NewView help file not found' );
4258
4259 LoadSupportDLL;
4260
4261 LogEvent(LogStartup, 'WMOpened: SetLayout');
4262
4263 // direct access the field to suppress updates done by the setter
4264 if CmdLineParameters.getHelpManagerFlag then
4265 FShowLeftPanel := Settings.ShowLeftPanel_Help
4266 else
4267 FShowLeftPanel := Settings.ShowLeftPanel_Standalone;
4268
4269 SetLayout;
4270
4271// ProfileEvent( 'Apply settings' );
4272// ApplySettings;
4273
4274 LogEvent(LogStartup, 'Enable controls');
4275 EnableControls;
4276
4277// ProfileEvent( 'ReadWindowPos' );
4278// ReadWindowPos( Self );
4279
4280 LogEvent(LogStartup, 'Finish paint');
4281 Update;
4282
4283 if not CmdLineParameters.getHelpManagerFlag then
4284 begin
4285 LogEvent(LogStartup, 'Check environment vars');
4286 CheckEnvironmentVars;
4287
4288 if CmdLineParameters.getShowUsageFlag then
4289 begin
4290 LogEvent(LogStartup, 'Showing usage');
4291 ShowUsage;
4292 end;
4293 end;
4294
4295 HelpManagerWindows.Add( pointer( CmdLineParameters.getHelpManagerWindow ) );
4296
4297 if CmdLineParameters.getFileNames(Settings.StartupHelp) <> '' then
4298 begin
4299 // open specified files
4300 Filenames := TStringList.Create;
4301
4302 StrExtractStringsIgnoreEmpty(Filenames, cmdLineParameters.getFileNames(Settings.StartupHelp), ['+'], #0);
4303
4304 LogEvent(LogStartup, 'Call OpenFiles');
4305
4306 OpenFirstTopic := true;
4307
4308 if ( CmdLineParameters.getSearchText <> '' )
4309 OR CmdLineParameters.getSearchFlag
4310 OR CmdLineParameters.getHelpManagerFlag
4311 then
4312 // if we're going to search, don't open first topic
4313 // don't open first topic if we're online help
4314 // in case we are wanting to show a specific topic
4315 // - saves time/flicker
4316 OpenFirstTopic := false;
4317
4318 OpenFiles( Filenames,
4319 CmdLineParameters.getWindowTitle,
4320 OpenFirstTopic );
4321
4322 Filenames.Destroy;
4323
4324 if not CmdLineParameters.getSearchFlag
4325 and not CmdLineParameters.getGlobalSearchFlag
4326 and (CmdLineParameters.getSearchText <> '') then
4327 begin
4328 // search in contents only!
4329 LogEvent(LogStartup, 'Do startup topic search for: "' + CmdLineParameters.getSearchText + '"');
4330
4331 StartupTopicSearch( CmdLineParameters.getSearchText );
4332 end
4333 else if CmdLineParameters.getSearchFlag then
4334 begin
4335 // search in specified files
4336 LogEvent(LogStartup, 'Do search for topic');
4337 DisplaySearch;
4338
4339 SearchFor( CmdLineParameters.getSearchText );
4340 end;
4341 end;
4342
4343 if NOT CmdLineParameters.getShowUsageFlag
4344 AND CmdLineParameters.getGlobalSearchFlag then
4345 begin
4346 // Global search
4347 LogEvent(LogStartup, 'Do global search: ' + CmdLineParameters.getSearchText);
4348 DoGlobalSearch( CmdLineParameters.getSearchText );
4349 end;
4350
4351 LogEvent(LogStartup, 'Open finished');
4352
4353 if CmdLineParameters.getHelpManagerFlag then
4354 begin
4355 // Tell helpmanager(s) our window handle
4356 PostHelpManagerMessage( NHM_VIEWER_READY,
4357 Handle,
4358 0 );
4359 end;
4360
4361 M1:= MemAvail;
4362
4363 StartingUp := false;
4364
4365 // ALT 20231023 handle system modal owner
4366 g_LastSysModalWindow := WinQuerySysModalWindow( HWND_DESKTOP );
4367 if g_LastSysModalWindow <> NULLHANDLE then
4368 begin
4369 WinSetSysModalWindow( HWND_DESKTOP, Frame.Handle );
4370 end;
4371
4372 LogEvent(LogStartup, 'RUN PROGRAM');
4373end;
4374
4375Procedure TMainForm.MainFormOnResize (Sender: TObject);
4376Begin
4377 if not Visible then
4378 exit;
4379 if Handle = 0 then
4380 exit;
4381
4382 SetLayout;
4383
4384End;
4385
4386Function TMainForm.GetShowLeftPanel: boolean;
4387begin
4388 Result := FShowLeftPanel;
4389end;
4390
4391Procedure TMainForm.SetShowLeftPanel( Value: boolean );
4392begin
4393 ShowLeftPanelMI.Checked := Value;
4394 if Value = FShowLeftPanel then
4395 exit;
4396 FShowLeftPanel := Value;
4397 if FShowLeftPanel then
4398 NotebookOnPageChanged( self ) // make sure page is updated
4399 else
4400 FocusFirstHelpWindow;
4401 EnableControls;
4402 SetLayout;
4403end;
4404
4405Procedure TMainForm.VSplitBarOnChange (NewSplit: LongInt);
4406Begin
4407 if VSplitBar.Left < 30 then
4408 begin
4409 ShowLeftPanel := false
4410 end
4411 else
4412 begin
4413 Settings.LeftPanelWidth := VSplitBar.Left;
4414 ShowLeftPanel := true;
4415 end;
4416 SetLayout;
4417End;
4418
4419// Set the layout of the main form
4420Procedure TMainForm.SetLayout;
4421var
4422 RealClientHeight : longint;
4423 CoolbarSpace: longint;
4424 TextHeight: longint;
4425Begin
4426 TextHeight := Canvas.TextHeight( 'S' );
4427 Tabset.Height := TextHeight + 5;
4428
4429 Coolbar.Visible := Settings.ToolbarStyle <> tsNone;
4430
4431 case Settings.ToolbarStyle of
4432 tsImages:
4433 Coolbar.Height := Coolbar.Sections[ 0 ].Width;
4434 tsText:
4435 Coolbar.Height := TextHeight + 5;
4436 tsImagesAndText:
4437 CoolBar.Height := ButtonImages.GetBitmapReference(0).Width + TextHeight + 10;
4438 end;
4439
4440 CoolbarSpace := Coolbar.Height;
4441 if not Coolbar.Visible then
4442 CoolbarSpace := 0;
4443
4444 StatusPanel.Left:= 0;
4445 StatusPanel.Width:= ClientWidth div 2 - 2;
4446 StatusPanel.Height := TextHeight + Font.InternalLeading + 2;
4447
4448 ProgressPanel.Left:= ClientWidth div 2 + 2;
4449 ProgressPanel.Width:= ClientWidth - ProgressPanel.Left;
4450 ProgressPanel.Height := TextHeight + Font.InternalLeading + 2;
4451
4452 Notebook.Bottom := StatusPanel.Height + 3;
4453 VSplitBar.Bottom := Notebook.Bottom;
4454 DisplayPanel.Bottom := Notebook.Bottom;
4455
4456 RealClientHeight := ClientHeight
4457 - CoolbarSpace
4458 - Notebook.Bottom;
4459
4460 LogEvent(LogStartup, 'TMainForm.SetLayout');
4461 LogEvent(LogStartup, ' RealClientHeight: ' + IntToStr( RealClientHeight ));
4462
4463 LogEvent(LogStartup, ' Form Width: ' + IntToStr( Width ));
4464 LogEvent(LogStartup, ' Form Height: ' + IntToStr( Height ) );
4465 LogEvent(LogStartup, ' Form ClientWidth: ' + IntToStr( ClientWidth ) );
4466 LogEvent(LogStartup, ' Form ClientHeight: ' + IntToStr( ClientHeight ) );
4467 LogEvent(LogStartup, ' CoolBar.Height: ' + IntToStr( CoolBar.Height ) );
4468 LogEvent(LogStartup, ' CoolBar.Bottom: ' + IntToStr( CoolBar.Bottom ) );
4469
4470 if CurrentOpenFiles.Count > 0 then
4471 VSplitBar.Width := Max( 5, Canvas.TextWidth( ' ' ) )
4472 else
4473 VSplitBar.Width := 0;
4474
4475 VSplitBar.Height := RealClientHeight;
4476
4477 if Settings.LeftPanelWidth > ClientWidth - 50 then
4478 Settings.LeftPanelWidth := ClientWidth - 50;
4479 if Settings.LeftPanelWidth < 50 then
4480 Settings.LeftPanelWidth := 50;
4481
4482 if ShowLeftPanel then
4483 begin
4484 VSplitBar.Left := Settings.LeftPanelWidth;
4485 VSplitBar.Hint := SplitBarDblClickToHide;
4486 end
4487 else
4488 begin
4489 VSplitBar.Left := 0;
4490 VSplitBar.Hint := SplitBarDblClickToShow;
4491 end;
4492
4493 Tabset.Left := 0;
4494 Tabset.Width := VSplitBar.Left;
4495 Tabset.Bottom := ClientHeight
4496 - CoolbarSpace
4497 - Tabset.Height;
4498
4499 Notebook.Left := 0;
4500 Notebook.Width := VSplitBar.Left;
4501 Notebook.Height := RealClientHeight
4502 - Tabset.Height
4503 - 3;
4504
4505 DisplayPanel.Left:= VSplitBar.Left + VSplitBar.Width;
4506 DisplayPanel.Width:= ClientWidth - DisplayPanel.Left;
4507 DisplayPanel.Height := RealClientHeight;
4508 LogEvent(LogStartup, ' DisplayPanel.Width: ' + IntToStr( DisplayPanel.Width ) );
4509 LogEvent(LogStartup, ' DisplayPanel.Height: ' + IntToStr( DisplayPanel.Height ) );
4510 LogEvent(LogStartup, ' DisplayPanel.Bottom: ' + IntToStr( DisplayPanel.Bottom ) );
4511
4512 ProgressBar.Left:= 1;
4513 ProgressBar.Bottom:= 1;
4514 ProgressBar.Width:= ProgressPanel.Width - 2;
4515 ProgressBar.Height:= ProgressPanel.Height - 2;
4516
4517 // Layout the visible help windows also
4518 LayoutWindowList( Windows );
4519End;
4520
4521// Lay out the specified list of help windows
4522Procedure TMainForm.LayoutWindowList( WindowList: TList );
4523var
4524 Window: THelpWindow;
4525 WindowIndex: longint;
4526begin
4527 for WindowIndex:= 0 to WindowList.Count - 1 do
4528 begin
4529 Window:= WindowList[ WindowIndex ];
4530 Window.SetLayout;
4531 end;
4532end;
4533
4534Procedure TMainForm.FindNextMIOnClick (Sender: TObject);
4535begin
4536 if FindText = '' then
4537 begin
4538 FindMIOnClick( sender );
4539 exit;
4540 end;
4541
4542 if GetActiveWindow = nil then
4543 begin
4544 DoErrorDlg( FindTitle,
4545 FindSelectWindowError );
4546 exit;
4547 end;
4548
4549 DoFind( foFromCurrent );
4550end;
4551
4552Procedure TMainForm.DoFind( FindOrigin: TFindOrigin );
4553var
4554 Window: THelpWindow;
4555begin
4556 SetWaitCursor;
4557 Window := GetActiveWindow;
4558 if not Window.View.Find( FindOrigin, FindText ) then
4559 begin
4560 SetStatus( TextNotFoundMsg );
4561 Beep( 1000, 100 );
4562 end;
4563 ClearWaitCursor;
4564End;
4565
4566Procedure TMainForm.FindMIOnClick (Sender: TObject);
4567begin
4568 if GetActiveWindow = nil then
4569 begin
4570 DoErrorDlg( FindTitle,
4571 FindSelectWindowError );
4572 exit;
4573 end;
4574 if not DoInputQuery( FindTitle,
4575 FindPrompt,
4576 FindText ) then
4577 exit;
4578
4579 DoFind( foFromStart );
4580End;
4581
4582Procedure TMainForm.IndexSearchEditOnScan (Sender: TObject;
4583 Var KeyCode: TKeyCode);
4584Begin
4585 case KeyCode of
4586 kbCUp:
4587 begin
4588 if IndexListBox.ItemIndex > 0 then
4589 IndexListBox.ItemIndex:= IndexListBox.ItemIndex - 1;
4590 KeyCode:= kbNull;
4591 end;
4592
4593 kbCDown:
4594 begin
4595 if IndexListBox.ItemIndex < IndexListBox.Items.Count - 1 then
4596 IndexListBox.ItemIndex:= IndexListBox.ItemIndex + 1;
4597 KeyCode:= kbNull;
4598 end;
4599
4600 kb_VK + VK_NEWLINE:
4601 begin
4602 DisplaySelectedIndexTopic;
4603 end;
4604 end;
4605
4606End;
4607
4608Procedure TMainForm.IndexSearchEditOnChange (Sender: TObject);
4609var
4610 tmpMatchIndex : longint;
4611 tmpSearchText: string;
4612 i : longint;
4613Begin
4614 if InIndexSearch then
4615 exit;
4616
4617 tmpMatchIndex := -1;
4618 tmpSearchText := trim(IndexSearchEdit.Text);
4619
4620 for i := 0 to DisplayedIndex.Count - 1 do
4621 begin
4622 if StrStartsWithIgnoringCase(DisplayedIndex[i], tmpSearchText) then
4623 begin
4624 tmpMatchIndex := i;
4625 break;
4626 end;
4627 end;
4628
4629 if tmpMatchIndex = -1 then
4630 exit;
4631
4632 InIndexSearch:= true;
4633
4634 if IndexListBox.ItemIndex <> tmpMatchIndex then
4635 IndexListBox.ItemIndex := tmpMatchIndex;
4636
4637 InIndexSearch:= false;
4638End;
4639
4640Procedure TMainForm.FileInformationMIOnClick (Sender: TObject);
4641var
4642 FileIndex: longint;
4643 HelpFile: THelpFile;
4644
4645 TotalTopicCount: longint;
4646 TotalIndexCount: longint;
4647 TotalFileSize: longint;
4648
4649Begin
4650 TotalTopicCount := 0;
4651 TotalIndexCount := 0;
4652 TotalFileSize := 0;
4653
4654 with InformationForm.InformationMemo do
4655 begin
4656 BeginUpdate;
4657 Lines.Clear;
4658 Lines.Add( FilesInfoTitle );
4659 for FileIndex := 0 to CurrentOpenFiles.Count - 1 do
4660 begin
4661 HelpFile := CurrentOpenFiles[ FileIndex ];
4662
4663 Lines.Add( FilesInfoFilename + HelpFile.FileName );
4664 Lines.Add( FilesInfoFileTitle
4665 + HelpFile.Title );
4666 Lines.Add( FilesInfoTopicCount
4667 + IntToStr( HelpFile.TopicCount ) );
4668 Lines.Add( FilesInfoIndexCount
4669 + IntToStr( HelpFile.Index.Count ) );
4670 Lines.Add( FilesInfoDictionaryCount
4671 + IntToStr( HelpFile.DictionaryCount ) );
4672 Lines.Add( FilesInfoFileSize
4673 + IntToStr( HelpFile.FileSize ) );
4674
4675 inc( TotalTopicCount, HelpFile.TopicCount );
4676 inc( TotalIndexCount, HelpFile.Index.Count );
4677 inc( TotalFileSize, HelpFile.FileSize );
4678
4679 end;
4680
4681 Lines.Add( '' );
4682 Lines.Add( FilesInfoTotalTopicCount
4683 + IntToStr( TotalTopicCount ) );
4684 Lines.Add( FilesInfoTotalIndexCount
4685 + IntToStr( TotalIndexCount ) );
4686 Lines.Add( FilesInfoTotalFileSize
4687 + IntToStr( TotalFileSize ) );
4688 Lines.Add( '' );
4689
4690 EndUpdate;
4691 end;
4692 InformationForm.ShowModal;
4693End;
4694
4695Procedure TMainForm.DisplaySelectedSearchResultTopic;
4696var
4697 Topic: TTopic;
4698Begin
4699 if SearchResultsListBox.ItemIndex = -1 then
4700 exit;
4701 if SelectedObject( SearchResultsListBox ) = nil then
4702 // the "no results" place holder
4703 exit;
4704
4705 Topic := SelectedObject( SearchResultsListBox ) as TTopic;
4706 DisplayTopic( Topic );
4707End;
4708
4709Procedure TMainForm.SearchTextEditOnScan (Sender: TObject;
4710 Var KeyCode: TKeyCode);
4711Begin
4712 case KeyCode of
4713 kbCUp:
4714 begin
4715 if SearchResultsListBox.ItemIndex > 0 then
4716 SearchResultsListBox.ItemIndex := SearchResultsListBox.ItemIndex - 1;
4717 KeyCode := kbNull;
4718 SearchResultsListBox.Focus;
4719 end;
4720
4721 kbCDown:
4722 begin
4723 if SearchResultsListBox.ItemIndex < SearchResultsListBox.Items.Count - 1 then
4724 SearchResultsListBox.ItemIndex := SearchResultsListBox.ItemIndex + 1;
4725 KeyCode := kbNull;
4726 SearchResultsListBox.Focus;
4727 end;
4728 end;
4729End;
4730
4731Procedure TMainForm.SearchButtonOnClick (Sender: TObject);
4732Begin
4733 DoSearch;
4734End;
4735
4736// Matches old stupid View algorithm
4737Procedure TMainForm.StartupTopicSearch( const SearchText: string );
4738var
4739 i: longint;
4740 HelpFile: THelpFile;
4741 Topic: TTopic;
4742 // s: string;
4743begin
4744 // search files in order they are open
4745 for i := 0 to CurrentOpenFiles.Count - 1 do
4746 begin
4747 HelpFile := THelpFile( CurrentOpenFiles[ i ] );
4748
4749 // look for a topic whose title starts with the searchtext
4750 Topic := HelpFile.FindTopicByTitleStartsWith( SearchText );
4751
4752 if Topic = nil then
4753 // look for an index entry that starts with the searchtext
4754 Topic := HelpFile.FindTopicByIndexStartsWith( SearchText );
4755
4756 if Topic = nil then
4757 // look for a topic whose title contains the searchtext
4758 Topic := HelpFile.FindTopicByTitleContains( SearchText );
4759
4760 if Topic = nil then
4761 // look for an index entry that contains the searchtext
4762 Topic := HelpFile.FindTopicByIndexContains( SearchText );
4763
4764 if Topic <> nil then
4765 begin
4766 // found something, display it (don't keep searching files)
4767 DisplayTopic( Topic );
4768 exit;
4769 end;
4770 end;
4771 DoErrorDlg( SearchTitle, TextNotFoundMsg );
4772end;
4773
4774Procedure TMainForm.SearchFor( const SearchText: string );
4775begin
4776 SearchTextEdit.Text := SearchText;
4777 DisplaySearch;
4778 SearchResultsListBox.Focus;
4779
4780 // force repaint of everything before we start searching.
4781 Update;
4782
4783 DoSearch;
4784end;
4785
4786Procedure TMainForm.ClearAllWordSequences;
4787var
4788 i: longint;
4789 FileWordSequences: TList;
4790 HelpFile: THelpFile;
4791begin
4792 if AllFilesWordSequences = nil then
4793 exit;
4794
4795 for i := 0 to AllFilesWordSequences.Count - 1 do
4796 begin
4797 FileWordSequences := AllFilesWordSequences[ i ];
4798 HelpFile := CurrentOpenFiles[ i ];
4799 ClearWordSequences( FileWordSequences, HelpFile.DictionaryCount );
4800 FileWordSequences.Destroy;
4801 end;
4802 AllFilesWordSequences.Clear;
4803end;
4804
4805// Perform search for text in searchedit.
4806Procedure TMainForm.DoSearch;
4807var
4808 SearchResults: TList;
4809 SearchText: string;
4810 FileIndex: longint;
4811 HelpFile: THelpFile;
4812 TopicIndex: longint;
4813 Topic: TTopic;
4814 FileWordSequences: TList;
4815 Query: TTextSearchQuery;
4816begin
4817 SearchText := Trim( SearchTextEdit.Text );
4818
4819 SearchResultsListBox.Clear;
4820
4821 if SearchText = '' then
4822 exit;
4823
4824 SearchResultsListBox.Items.Add( SearchingMsg );
4825 SetStatus( SearchingMsg );
4826
4827 try
4828 Query := TTextSearchQuery.Create( SearchText );
4829 except
4830 on e: ESearchSyntaxError do
4831 begin
4832 DoErrorDlg( SearchTitle,
4833 SearchSyntaxError
4834 + e.Message );
4835 exit;
4836 end;
4837 end;
4838
4839 ClearAllWordSequences;
4840
4841 SetWaitCursor;
4842
4843 SearchResults := TList.Create;
4844
4845 // Search open help file
4846 for FileIndex := 0 to CurrentOpenFiles.Count - 1 do
4847 begin
4848 HelpFile := CurrentOpenFiles[ FileIndex ];
4849
4850 FileWordSequences := TList.Create;
4851
4852 try
4853 SearchHelpFile( HelpFile,
4854 Query,
4855 SearchResults,
4856 FileWordSequences );
4857 except
4858 on E: EHelpFileException do
4859 begin
4860 DoErrorDlg( ErrorTitle, E.Message );
4861 Query.Destroy;
4862 ClearWaitCursor;
4863 exit;
4864 end;
4865 end;
4866
4867 AllFilesWordSequences.Add( FileWordSequences );
4868
4869 end;
4870
4871 // Sort results across all files by relevance
4872 SearchResults.Sort( TopicRelevanceCompare );
4873
4874 // Load topics into search results list.
4875 SearchResultsListBox.BeginUpdate;
4876 SearchResultsListBox.Clear;
4877
4878 for TopicIndex := 0 to SearchResults.Count - 1 do
4879 begin
4880 Topic := SearchResults[ TopicIndex ];
4881 SearchResultsListBox.Items.AddObject( Topic.Title
4882 + ' ['
4883 + IntToStr( Topic.SearchRelevance )
4884 + ']',
4885 Topic );
4886 end;
4887
4888 EnableControls;
4889 if SearchResultsListBox.Items.Count > 0 then
4890 // there are some search matches, so highlight words
4891 ViewHighlightSearchWordsMI.Checked := true;
4892
4893 SearchResultsListBox.ItemIndex := -1;
4894 SearchResultsListBox.EndUpdate;
4895
4896 Query.Destroy;
4897 SearchResults.Destroy;
4898
4899 if SearchResultsListBox.Items.Count > 0 then
4900 begin
4901 SearchResultsListBox.ItemIndex := 0;
4902 end
4903 else
4904 begin
4905 SearchResultsListBox.Items.Add( NoSearchMatchesMsg
4906 + ': '
4907 + SearchText );
4908 RefreshWindows( Windows ); // update to remove old highlights
4909 end;
4910 SetStatus( SearchFoundMsgA
4911 + IntToStr( SearchResultsListBox.Items.Count )
4912 + SearchFoundMsgB
4913 + StrInDoubleQuotes(SearchText)
4914 );
4915
4916 ClearWaitCursor;
4917
4918 DisplaySelectedSearchResultTopic;
4919
4920End;
4921
4922Procedure TMainForm.FileSaveAsMIOnClick (Sender: TObject);
4923var
4924 F: File;
4925 EntryText: PChar;
4926 TextLength: longint;
4927 Window: THelpWindow;
4928 Filename: string;
4929Begin
4930 Window := GetActiveWindow;
4931 if Window = nil then
4932 begin
4933 DoErrorDlg( FileSaveTitle,
4934 FileSaveSelectWindowError );
4935 exit;
4936 end;
4937
4938 if DoSaveFileDialog( FileSaveTitle,
4939 AllFilesDesc + '|*',
4940 DefaultSaveTopicFilename,
4941 Settings.LastSaveDirectory,
4942 Filename ) then
4943 begin
4944 if FileExists( Filename ) then
4945 if not DoConfirmDlg( FileSaveTitle,
4946 ReplaceFilePromptA
4947 + Filename
4948 + ReplaceFilePromptB ) then
4949 exit;
4950 System.Assign( F, Filename );
4951
4952 try
4953 Rewrite( F );
4954 except
4955 on E: Exception do
4956 begin
4957 DoErrorDlg( FileSaveTitle,
4958 UnableToSaveError
4959 + Filename
4960 + ': '
4961 + E.Message );
4962 exit;
4963 end;
4964 end;
4965
4966 // find out length of (plain) text
4967 TextLength := Window.View.CopyTextToBuffer( nil, -1 );
4968
4969 // allocate space
4970 EntryText:= StrAlloc( TextLength );
4971
4972 // get the plain text
4973 Window.View.CopyTextToBuffer( EntryText, TextLength );
4974
4975 // save to file
4976 System.BlockWrite( F, EntryText^, TextLength );
4977
4978 // free space
4979 StrDispose( EntryText );
4980
4981 System.Close( F );
4982 end;
4983End;
4984
4985Procedure TMainForm.OptionsMIOnClick (Sender: TObject);
4986begin
4987 DoOptions;
4988end;
4989
4990Procedure TMainForm.DoOptions;
4991Begin
4992 EnsureOptionsFormLoaded;
4993
4994 GetColors; // in case changed by drag drop
4995
4996 if OptionsForm.ShowModal = mrOK then
4997 begin
4998 ApplySettings;
4999 SetLayout;
5000 RefreshFontSubstitutions;
5001 RefreshWindows( Windows );
5002 end;
5003End;
5004
5005Procedure TMainForm.ShowUsage;
5006begin
5007 DoMessageDlg( UsageTitle,
5008 UsageText1 + StrCRLF
5009 + UsageText2 + StrCRLF
5010 + UsageText3 + StrCRLF
5011 + UsageText4 + StrCRLF
5012 + UsageText5 + StrCRLF
5013 + UsageText6 + StrCRLF
5014 + UsageText7 + StrCRLF
5015 + UsageText8 );
5016end;
5017
5018Procedure TMainForm.TabSetOnChange (Sender: TObject; NewTab: LongInt;
5019 Var AllowChange: Boolean);
5020Begin
5021 NoteBook.PageIndex := NewTab;
5022End;
5023
5024Procedure TMainForm.NotebookOnSetupShow (Sender: TObject);
5025var
5026 btnWidth: integer;
5027 btnHeight: integer;
5028Begin
5029 btnWidth := Canvas.TextWidth('M') * 8;
5030 btnHeight := trunc( Canvas.TextHeight('M') * 1.5 );
5031
5032 DeleteNoteButton.Width := btnWidth;
5033 DeleteNoteButton.Height := btnHeight;
5034 GotoNoteButton.Width := btnWidth;
5035 GotoNoteButton.Height := btnHeight;
5036 GotoNoteButton.Left := btnWidth + 10;
5037 AddNoteButton.Width := btnWidth;
5038 AddNoteButton.Height := btnHeight;
5039 AddNoteButton.Bottom := btnHeight + 5;
5040 EditNoteButton.Width := btnWidth;
5041 EditNoteButton.Height := btnHeight;
5042 EditNoteButton.Left := btnWidth + 10;
5043 EditNoteButton.Bottom := btnHeight + 5;
5044
5045 ContentsOutline.xStretch := xsFrame;
5046 ContentsOutline.yStretch := ysFrame;
5047
5048 IndexSearchEdit.yAlign := yaTop;
5049 IndexSearchEdit.xStretch := xsFrame;
5050 IndexListBox.yStretch := ysFrame;
5051 IndexListBox.xStretch := xsFrame;
5052
5053 SearchTextEdit.yAlign := yaTop;
5054 SearchTextEdit.xStretch := xsFrame;
5055 SearchButton.yAlign := yaTop;
5056 SearchButton.xAlign := xaRight;
5057 SearchResultsListBox.xStretch := xsFrame;
5058 SearchResultsListBox.yStretch := ysFrame;
5059
5060 NotesListBox.Bottom := 2 * btnHeight + 10;
5061 NotesListBox.Height := Notebook.ClientHeight - NotesListBox.Bottom;
5062
5063 NotesListBox.xStretch := xsFrame;
5064 NotesListBox.yStretch := ysFrame;
5065End;
5066
5067Procedure TMainForm.EnableControls;
5068var
5069 BackEnabled: boolean;
5070 ForwardEnabled: boolean;
5071 FileOpen: boolean;
5072 WindowOpen: boolean;
5073 AtTop: boolean;
5074 AtBottom: boolean;
5075begin
5076 ViewContentsMI.Checked := ShowLeftPanel and ( Notebook.PageIndex = piContents );
5077 ViewIndexMI.Checked := ShowLeftPanel and ( Notebook.PageIndex = piIndex );
5078 ViewSearchMI.Checked := ShowLeftPanel and ( Notebook.PageIndex = piSearch );
5079 ViewNotesMI.Checked := ShowLeftPanel and ( Notebook.PageIndex = piNotes );
5080
5081 BackEnabled := CurrentHistoryIndex > 0;
5082 ForwardEnabled := CurrentHistoryIndex < PageHistory.Count - 1;
5083
5084 FileOpen := CurrentOpenFiles.Count > 0;
5085 WindowOpen := Windows.Count > 0;
5086
5087 ViewContentsMI.Enabled := FileOpen;
5088 ViewIndexMI.Enabled := FileOpen;
5089 ViewSearchMI.Enabled := FileOpen;
5090 ViewNotesMI.Enabled := FileOpen;
5091
5092 ShowLeftPanelMI.Enabled := FileOpen;
5093
5094 Coolbar.Sections[ ciBack ].Disabled := not BackEnabled;
5095 NavigateBackMI.Enabled := BackEnabled;
5096 Coolbar.Sections[ ciForward ].Disabled := not ForwardEnabled;
5097 NavigateForwardMI.Enabled := ForwardEnabled;
5098
5099 FileSaveAsMI.Enabled := FileOpen;
5100
5101 Coolbar.Sections[ ciPrint ].Disabled := not FileOpen;
5102 PrintMI.Enabled := FileOpen;
5103 FileInformationMI.Enabled := FileOpen;
5104
5105 Coolbar.Sections[ ciAddBookmark ].Disabled := not FileOpen;
5106 AddBookmarkMI.Enabled := FileOpen;
5107 EditBookmarksMI.Enabled := FileOpen;
5108 Coolbar.Sections[ ciAddNote ].Disabled := not FileOpen;
5109 AddNoteMI.Enabled := FileOpen;
5110
5111 if ContentsOutline.SelectedNode <> nil then
5112 begin
5113 AtTop := ContentsOutline.NextNodeUp( ContentsOutline.SelectedNode, false ) = nil;
5114 AtBottom := ContentsOutline.NextNodeDown( ContentsOutline.SelectedNode, false ) = nil;
5115 end;
5116
5117 NavigateNextMI.Enabled := FileOpen
5118 and ( ContentsOutline.SelectedNode <> nil )
5119 and ( not AtBottom );
5120 Coolbar.Sections[ ciNext ].Disabled := not NavigateNextMI.Enabled;
5121 NavigatePreviousMI.Enabled := FileOpen
5122 and ( ContentsOutline.SelectedNode <> nil )
5123 and ( not AtTop );
5124 Coolbar.Sections[ ciPrevious ].Disabled := not NavigatePreviousMI.Enabled;
5125
5126 FileCloseMI.Enabled := FileOpen;
5127
5128 FindMI.Enabled := WindowOpen;
5129 FindNextMI.Enabled := WindowOpen;
5130 CopyMI.Enabled := WindowOpen;
5131 SelectAllMI.Enabled := WindowOpen;
5132
5133 ViewExpandAllMI.Enabled := ContentsOutline.ChildCount > 0;
5134 ViewCollapseAllMI.Enabled := ContentsOutline.ChildCount > 0;
5135
5136 DebugTopicByResourceIDMI.Enabled := FileOpen;
5137 TopicByNameMI.Enabled := FileOpen;
5138
5139 ViewHighlightSearchWordsMI.Enabled := SearchResultsListBox.Items.Count > 0;
5140 if not ViewHighlightSearchWordsMI.Enabled then
5141 ViewHighlightSearchWordsMI.Checked := false;
5142
5143 ViewRefreshMI.Enabled := WindowOpen;
5144
5145 EnableSearchButton;
5146 EnableNotesControls;
5147
5148 VSplitBar.Visible := FileOpen;
5149 if not FileOpen then
5150 begin
5151 SetShowLeftPanel( false );
5152 end;
5153
5154
5155end;
5156
5157Procedure TMainForm.NavigateBackMIOnClick (Sender: TObject);
5158begin
5159 NavigateBack;
5160end;
5161
5162Procedure TMainForm.SaveNavigatePoint;
5163var
5164 NavPoint: TNavigatePoint;
5165begin
5166 // delete rest of history.
5167 while CurrentHistoryIndex < PageHistory.Count - 1 do
5168 begin
5169 NavPoint:= PageHistory.Objects[ CurrentHistoryIndex + 1 ] as TNavigatePoint;
5170 NavPoint.Destroy;
5171 PageHistory.Delete( CurrentHistoryIndex + 1 );
5172 end;
5173
5174 NavPoint:= TNavigatePoint.Create;
5175 SaveWindows( Windows, NavPoint.Windows, nil );
5176
5177 if ContentsOutline.SelectedNode <> nil then
5178 NavPoint.ContentsTopic:= ContentsOutline.SelectedNode.Data as TTopic
5179 else
5180 NavPoint.ContentsTopic:= nil;
5181
5182 if CurrentTopic <> nil then
5183 PageHistory.AddObject( CurrentTopic.Title, NavPoint )
5184 else
5185 PageHistory.AddObject( '', NavPoint );
5186
5187 inc( CurrentHistoryIndex );
5188
5189 CreateNavigateToMenuItems;
5190end;
5191
5192Procedure TMainForm.UpdateCurrentNavigatePoint;
5193var
5194 NavPoint: TNavigatePoint;
5195begin
5196 if CurrentHistoryIndex = -1 then
5197 exit;
5198
5199 NavPoint:= PageHistory.Objects[ CurrentHistoryIndex ] as TNavigatePoint;
5200
5201 DestroyListObjects( NavPoint.Windows );
5202 NavPoint.Windows.Clear;
5203
5204 SaveWindows( Windows, NavPoint.Windows, nil );
5205end;
5206
5207Procedure TMainForm.ClearPageHistory;
5208var
5209 i: longint;
5210 NavPoint: TNavigatePoint;
5211begin
5212 for i := 0 to PageHistory.Count - 1 do
5213 begin
5214 NavPoint := PageHistory.Objects[ i ] as TNavigatePoint;
5215 NavPoint.Destroy;
5216 end;
5217 PageHistory.Clear;
5218 CurrentHistoryIndex := -1;
5219 CreateNavigateToMenuItems;
5220 EnableControls;
5221end;
5222
5223Procedure TMainForm.SaveWindows( SourceList: TList;
5224 DestList: TList;
5225 Parent: TSavedHelpWindow );
5226
5227var
5228 WindowIndex: longint;
5229 Window: THelpWindow;
5230 WindowCopy: TSavedHelpWindow;
5231begin
5232 // limit storage to only what's need since list will be static.
5233 DestList.Capacity := SourceList.Count;
5234 for WindowIndex := 0 to SourceList.Count - 1 do
5235 begin
5236 Window := SourceList[ WindowIndex ];
5237 WindowCopy := TSavedHelpWindow.Create;
5238 WindowCopy.Parent := Parent;
5239 WindowCopy.Rect.Assign( Window.Rect );
5240 WindowCopy.Topic := Window.Topic;
5241 WindowCopy.Group := Window.Group;
5242 WindowCopy.TopCharIndex := Window.View.TopCharIndex;
5243 SaveWindows( Window.ChildWindows, WindowCopy.ChildWindows, WindowCopy );
5244 DestList.Add( WindowCopy );
5245 end;
5246end;
5247
5248Procedure TMainForm.DisplayWindows( WindowList: TList;
5249 Parent: THelpWindow );
5250var
5251 WindowIndex: longint;
5252 WindowCopy: TSavedHelpWindow;
5253 NewWindow: THelpWindow;
5254begin
5255 for WindowIndex := 0 to WindowList.Count - 1 do
5256 begin
5257 WindowCopy := WindowList[ WindowIndex ];
5258 NewWindow := OpenWindow( WindowCopy.Topic,
5259 WindowCopy.Group,
5260 Parent,
5261 WindowCopy.Rect,
5262 false ); // don't follow links
5263 NewWindow.View.TopCharIndex := WindowCopy.TopCharIndex;
5264 DisplayWindows( WindowCopy.ChildWindows, NewWindow );
5265 end;
5266end;
5267
5268Procedure TMainForm.CreateNavigateToMenuItems;
5269var
5270 MenuItem: TMenuItem;
5271 i: integer;
5272begin
5273 // clear existing items
5274 DestroyListObjects( NavigateToMenuItems );
5275 NavigateToMenuItems.Clear;
5276
5277 if CurrentHistoryIndex > 0 then
5278 begin
5279 // We are going to add some items, so
5280 // add a seperator from the rest of the menu first
5281 MenuItem := TMenuItem.Create( self );
5282 MenuItem.Caption:= '-';
5283 NavigateMenu.Add( MenuItem );
5284 NavigateToMenuItems.Add( MenuItem );
5285 end;
5286
5287 i := CurrentHistoryIndex - 1; // don't include the current history item
5288 while ( ( i >= 0 )
5289 and ( i > CurrentHistoryIndex - 10 ) ) do
5290 begin
5291 MenuItem := TMenuItem.Create( self );
5292 MenuItem.Caption := PageHistory[ i ];
5293 MenuItem.Hint := GoBackHint
5294 + StrInDoubleQuotes( PageHistory[ i ] );
5295 MenuItem.OnClick := OnNavigateToMenuItemClick;
5296 MenuItem.Tag := i;
5297
5298 NavigateMenu.Add( MenuItem );
5299 NavigateToMenuItems.Add( MenuItem );
5300 dec( i );
5301 end;
5302end;
5303
5304Procedure TMainForm.NavigateToPoint( NavPoint: TNavigatePoint );
5305begin
5306 Navigating := true;
5307
5308 // close current windows
5309 CloseWindows;
5310
5311 // Display windows for the navigate point
5312 DisplayWindows( NavPoint.Windows, nil );
5313
5314 // Select the contents topic
5315 ContentsOutline.SetSelectedObject( NavPoint.ContentsTopic );
5316
5317 // Update the navigate menu (since a different set of
5318 // back-points are now available)
5319 CreateNavigateToMenuItems;
5320
5321 // Make the topic windows visible
5322 ShowWindows;
5323
5324 // Update back buttons etc...
5325 EnableControls;
5326
5327 Navigating := false;
5328end;
5329
5330Procedure TMainForm.NavigateToHistoryIndex( Index: longint );
5331var
5332 NavPoint: TNavigatePoint;
5333begin
5334 UpdateCurrentNavigatePoint;
5335 CurrentHistoryIndex := Index;
5336 NavPoint := PageHistory.Objects[ CurrentHistoryIndex ] as TNavigatePoint;
5337 NavigateToPoint( NavPoint );
5338end;
5339
5340Procedure TMainForm.NavigateForward;
5341Begin
5342 if CurrentHistoryIndex < PageHistory.Count - 1 then
5343 begin
5344 NavigateToHistoryIndex( CurrentHistoryIndex + 1 );
5345 end;
5346End;
5347
5348Procedure TMainForm.NavigateBack;
5349Begin
5350 if CurrentHistoryIndex > 0 then
5351 begin
5352 NavigateToHistoryIndex( CurrentHistoryIndex - 1 );
5353 end;
5354End;
5355
5356Procedure TMainForm.NavigatePreviousInContents;
5357begin
5358 ContentsOutline.GotoNextNodeUp;
5359 DisplaySelectedContentsTopic;
5360end;
5361
5362Procedure TMainForm.NavigateNextInContents;
5363begin
5364 ContentsOutline.GotoNextNodeDown;
5365 DisplaySelectedContentsTopic;
5366end;
5367
5368Procedure TMainForm.CorrectNotesPositions( Topic: TTopic;
5369 Text: pchar );
5370var
5371 NoteIndex: longint;
5372 Note: THelpNote;
5373 p: pchar;
5374 NextP: pchar;
5375 Element: TTextElement;
5376 TextIndex: longint;
5377begin
5378 NoteIndex := 0;
5379 for NoteIndex := 0 to Notes.Count - 1 do
5380 begin
5381 Note := Notes[ NoteIndex ];
5382 if Note.Topic = Topic then
5383 begin
5384 // this note belongs the the specified topic.
5385 p := Text;
5386
5387 while true do
5388 begin
5389 Element := ExtractNextTextElement( p, NextP );
5390 if Element.ElementType = teTextEnd then
5391 break;
5392 TextIndex := PCharPointerDiff( p, Text );
5393 if TextIndex >= Note.InsertPoint then
5394 begin
5395 // found a safe point to insert
5396 if TextIndex <> Note.InsertPoint then
5397 begin
5398 // correct it.
5399 Note.InsertPoint := TextIndex;
5400 end;
5401 break;
5402 end;
5403
5404 p := NextP;
5405 end;
5406 end;
5407 end;
5408end;
5409
5410Procedure TMainForm.InsertNotesIntoTopicText( Topic: TTopic;
5411 Text: TAString );
5412var
5413 NoteIndex: longint;
5414 Note: THelpNote;
5415 ActualInsertPoint: longword;
5416begin
5417 CorrectNotesPositions( Topic, Text.AsPChar );
5418
5419 for NoteIndex := 0 to Notes.Count - 1 do
5420 begin
5421 Note := Notes[ NoteIndex ];
5422 if Note.Topic = Topic then
5423 begin
5424 // Adjust insert point for any notes we have already inserted.
5425 ActualInsertPoint := FindActualNoteCharIndex( Note.InsertPoint,
5426 NoteIndex,
5427 Topic );
5428 RefreshNoteInsertInfo( NoteIndex );
5429 Text.Insert( ActualInsertPoint, Note.InsertText );
5430 end;
5431 end;
5432end;
5433
5434Procedure TMainForm.NavigatePreviousMIOnClick (Sender: TObject);
5435Begin
5436 NavigatePreviousInContents;
5437End;
5438
5439Procedure TMainForm.NavigateNextMIOnClick (Sender: TObject);
5440Begin
5441 NavigateNextInContents;
5442End;
5443
5444Function TMainForm.GetActiveWindow: THelpWindow;
5445var
5446 View: TRichTextView;
5447 FirstWindow: THelpWindow;
5448begin
5449 Result := nil;
5450 if Screen.ActiveControl is TRichTextView then
5451 begin
5452 View := Screen.ActiveControl as TRichTextView;
5453 Result := FindWindowFromView( View, Windows );
5454 end
5455 else if Windows.Count = 1 then
5456 begin
5457 FirstWindow := Windows[ 0 ];
5458 if FirstWindow.ChildWindows.Count = 0 then
5459 Result := FirstWindow;
5460 end;
5461end;
5462
5463Procedure TMainForm.CopyMIOnClick (Sender: TObject);
5464var
5465 Window: THelpWindow;
5466begin
5467 if ActiveControl = nil then
5468 exit;
5469
5470 if ActiveControl is TEdit then
5471 begin
5472 // this is for the edit controls in the left panel
5473 TEdit( ActiveControl ).CopyToClipboard;
5474 exit;
5475 end;
5476
5477 // else copy from rtv in active help window
5478
5479 Window := GetActiveWindow;
5480 if Window = nil then
5481 exit;
5482
5483 Window.View.CopySelectionToClipboard;
5484End;
5485
5486Procedure TMainForm.SelectAllMIOnClick (Sender: TObject);
5487var
5488 Window: THelpWindow;
5489begin
5490 Window:= GetActiveWindow;
5491 if Window = nil then
5492 begin
5493 DoErrorDlg( SelectAllTitle,
5494 SelectAllWindowError );
5495 exit;
5496 end;
5497 Window.View.SelectAll;
5498End;
5499
5500Procedure TMainForm.DebugShowCodesMIOnClick (Sender: TObject);
5501Begin
5502 DebugShowCodesMI.Checked:= not DebugShowCodesMI.Checked;
5503 RefreshWindows( Windows );
5504End;
5505
5506Procedure TMainForm.HelpProductInformationMIOnClick (Sender: TObject);
5507Begin
5508 EnsureProductInformationFormLoaded;
5509 ProductInformationForm.ShowModal;
5510End;
5511
5512Procedure TMainForm.OnOverLink ( Sender: TRichTextView; LinkString: String);
5513var
5514 Link: THelpLink;
5515 LinkIndex: longint;
5516 Window: THelpWindow;
5517 LinkedTopic: TTopic;
5518 Filename: string;
5519 SourceFile: THelpFile;
5520 URL: string;
5521 LinkDetails: string;
5522 tmpLinkDetails : TStringList;
5523 ProgramInfo : TSerializableStringList;
5524 ProgramPath, ProgramLink : string;
5525Begin
5526 LogEvent(LogDebug, 'OnOverLink: "' + LinkString + '"');
5527
5528 if StrStartsWith(LinkString, PARAM_LINK_NOTE) then
5529 begin
5530 SetStatus( EditNoteMsg )
5531 end
5532 else if StrStartsWith(LinkString, PARAM_LINK_PROGRAM) then
5533 begin
5534 ProgramInfo := TSerializableStringList.create;
5535// TODO check param here
5536
5537 ProgramInfo.readValuesFromSerializedString(StrSubstringFrom(LinkString, Length(PARAM_LINK_PROGRAM) + 2));
5538 ProgramPath := ProgramInfo.get(0);
5539 ProgramLink := ProgramInfo.get(1);
5540 TSerializableStringList.destroy;
5541
5542 // call LaunchProgram here to inherit the environment
5543 SetStatus( LinkMsg + ' ' + ProgramPath + ' ' + ProgramLink);
5544 end
5545 else if StrStartsWith(LinkString, PARAM_LINK_URL) then
5546 begin
5547 URL := StrSubstringFrom(LinkString, Length(PARAM_LINK_URL) + 2); //
5548
5549 SetStatus( LinkMsg + URL );
5550 end
5551 else if StrStartsWith(LinkString, PARAM_LINK_EXTERNAL) then
5552 begin
5553 LinkDetails := StrSubstringFrom(LinkString, Length(PARAM_LINK_EXTERNAL) + 2);
5554
5555 tmpLinkDetails := TStringList.Create;
5556 StrExtractStrings(tmpLinkDetails, LinkDetails, [' '], #0);
5557 LinkIndex := StrToInt(tmpLinkDetails[0]);
5558 tmpLinkDetails.Destroy;
5559
5560 Window := FindWindowFromView( Sender, Windows );
5561 SourceFile := Window.Topic.HelpFile as THelpFile;
5562 Filename := SourceFile.ReferencedFiles[ LinkIndex ];
5563 SetStatus( LinkMsg
5564 + StrInDoubleQuotes( Filename ) );
5565 end
5566 else
5567 begin
5568 Window := FindWindowFromView( Sender, Windows );
5569 LinkIndex := StrToInt( LinkString );
5570 Link := Window.Topic.Links[ LinkIndex ];
5571
5572 if Link is TFootnoteHelpLink then
5573 begin
5574 SetStatus( FootnoteMsg );
5575 end
5576 else
5577 begin
5578 LinkedTopic := FindTopicForLink( Link );
5579
5580 if LinkedTopic <> nil then
5581 begin
5582 SetStatus( LinkMsg
5583 + StrInDoubleQuotes( Trim( LinkedTopic.Title ) ) );
5584 end
5585 else
5586 begin
5587 SetStatus( UnknownLinkMsg );
5588 end;
5589 end;
5590 end;
5591End;
5592
5593Procedure TMainForm.OnNotOverLink ( Sender: TRichTextView; LinkString: String);
5594Begin
5595 SetStatus( '' );
5596end;
5597
5598Procedure TMainForm.OnClickLink ( Sender: TRichTextView; LinkString: String);
5599var
5600 Link: THelpLink;
5601 LinkIndex: longint;
5602 SourceWindow: THelpWindow;
5603 NoteIndex: longint;
5604 Window: THelpWindow;
5605 SourceFile: THelpFile;
5606 ProgramLink: string;
5607 ProgramPath: string;
5608 URL: string;
5609 LinkDetails: string;
5610 tmpLinkDetails : TStringList;
5611 ProgramInfo : TSerializableStringList;
5612Begin
5613 LogEvent(LogDebug, 'OnClickLink: "' + LinkString + '"');
5614
5615 if StrStartsWith(LinkString, PARAM_LINK_NOTE) then
5616 begin
5617 NoteIndex := StrToInt(StrSubstringFrom(LinkString, Length(PARAM_LINK_NOTE) + 2) );
5618 NotesListBox.ItemIndex := NoteIndex;
5619 EditNote( NoteIndex );
5620 end
5621 else if StrStartsWith(LinkString, PARAM_LINK_PROGRAM) then
5622 begin
5623 ProgramInfo := TSerializableStringList.create;
5624 ProgramInfo.readValuesFromSerializedString(StrSubstringFrom(LinkString, 9));
5625 ProgramPath := ProgramInfo.get(0);
5626 ProgramLink := ProgramInfo.get(1);
5627 TSerializableStringList.destroy;
5628
5629 // call LaunchProgram here to inherit the environment
5630 LogEvent(LogDisplay, 'LaunchProgram: "' + ProgramPath + '" "' + ProgramLink + '"');
5631 LaunchProgram(ProgramPath, ProgramLink, '');
5632 // TODO i18n
5633 SetStatus( 'Launched ' + ProgramPath );
5634 end
5635 else if StrLeft( LinkString, 3 ) = PARAM_LINK_URL then
5636 begin
5637 URL := StrSubstringFrom(LinkString, Length(PARAM_LINK_URL) + 2);
5638
5639 try
5640 LaunchURL(URL);
5641 except
5642 on E:Exception do
5643 begin
5644 DoErrorDlg('Error', E.Message);
5645 end;
5646 else raise;
5647 end;
5648
5649 // TODO i18n
5650 SetStatus('Opened ' + URL );
5651 end
5652 else if StrLeft( LinkString, 8 ) = PARAM_LINK_EXTERNAL then
5653 begin
5654 LinkDetails := StrSubstringFrom(LinkString, Length(PARAM_LINK_EXTERNAL) + 2);
5655
5656 Window := FindWindowFromView(Sender, Windows);
5657 SourceFile := Window.Topic.HelpFile as THelpFile;
5658
5659 tmpLinkDetails := TStringList.Create;
5660 StrExtractStrings(tmpLinkDetails, LinkDetails, [' '], #0);
5661 LinkIndex := StrToInt(tmpLinkDetails[0]);
5662 g_ExternalLinkFileName := SourceFile.ReferencedFiles[ LinkIndex ];
5663 g_ExternalLinkTopic := tmpLinkDetails[1];
5664 tmpLinkDetails.Destroy;
5665
5666 g_ExternalLinkSourceFilename := SourceFile.Filename;
5667 g_ExternalLinkKeepCurrent := true; // hm... what would be nice?
5668
5669 PostMsg( Self.Handle,
5670 WM_FOLLOWEXTERNALLINK,
5671 0,
5672 0 );
5673 end
5674 else
5675 begin
5676 SourceWindow := FindWindowFromView( Sender, Windows );
5677 LinkIndex := StrToInt( LinkString );
5678 Link := SourceWindow.Topic.Links[ LinkIndex ];
5679
5680 PostMsg( Self.Handle,
5681 WM_FOLLOWLINK,
5682 longint( Link ),
5683 longint( SourceWindow ) );
5684
5685 end;
5686End;
5687
5688Procedure TMainForm.OnWindowAboutToClose( Window: THelpWindow;
5689 var CanClose: boolean );
5690begin
5691 if Navigating then
5692 exit;
5693
5694 UpdateCurrentNavigatePoint; // Save it before close...
5695
5696 CanClose := true;
5697end;
5698
5699Procedure TMainForm.RemoveHelpWindowFromParent( Window: THelpWindow );
5700var
5701 ParentWindow: THelpWindow;
5702 WindowIndex: longint;
5703Begin
5704 if Navigating then
5705 exit;
5706
5707 if Window.ParentHelpWindow = nil then
5708 begin
5709 WindowIndex := Windows.IndexOf( Window );
5710 Windows.Delete( WindowIndex );
5711 end
5712 else
5713 begin
5714 ParentWindow := Window.ParentHelpWindow;
5715 WindowIndex := ParentWindow.ChildWindows.IndexOf( Window );
5716 ParentWindow.ChildWindows.Delete( WindowIndex );
5717 end;
5718end;
5719
5720Procedure TMainForm.OnWindowClose( Window: THelpWindow );
5721Begin
5722 if Navigating then
5723 exit;
5724
5725 RemoveHelpWindowFromParent( Window );
5726
5727 SaveNavigatePoint;
5728 EnableControls;
5729End;
5730
5731Procedure TMainForm.BackButtonOnClick (Sender: TObject);
5732Begin
5733 NavigateBack;
5734End;
5735
5736Procedure TMainForm.RTViewOnSetupShow (Sender: TObject);
5737Begin
5738End;
5739
5740Procedure TMainForm.ExitMIOnClick (Sender: TObject);
5741Begin
5742 Close;
5743End;
5744
5745Procedure TMainForm.CreateMRUMenuItems;
5746var
5747 MenuItem: TMenuItem;
5748 i: integer;
5749 FileName: string;
5750 FileNameIndex: longint;
5751 MRUText: string;
5752 MRUItem: TMRUItem;
5753begin
5754 DestroyListObjects( MRUMenuItems );
5755 MRUMenuItems.Clear;
5756
5757 // if there are Most Recently Used files
5758 if Settings.MRUList.Count > 0 then
5759 begin
5760 // create a seperator after Exit
5761 MenuItem:= TMenuItem.Create( self );
5762 MenuItem.Name := 'MRUSeparatorMI';
5763 MenuItem.Caption:= '-';
5764 FileMenu.Add( MenuItem );
5765 MRUMenuItems.Add( MenuItem );
5766 end;
5767
5768 // Add items for the MRU files
5769 for i:= 0 to Settings.MRUList.Count -1 do
5770 begin
5771 MRUItem := Settings.MRUList[ i ];
5772
5773 MenuItem := TMenuItem.Create( self );
5774
5775 MenuItem.Name := 'MRUItem' + IntToStr( i ) + 'MI';
5776 MRUText := MRUItem.Title;
5777 if Trim( MRUText ) = '' then
5778 begin
5779 // Take the filenames, less path, as caption...
5780 MRUText := '';
5781 for FileNameIndex := 0 to MRUItem.Filenames.Count - 1 do
5782 begin
5783 FileName := MRUItem.Filenames[ FileNameIndex ];
5784 FileName := ExtractFileName( FileName );
5785 FileName := ChangeFileExt( FileName, '' );// remove extension
5786
5787 if FileNameIndex > 0 then
5788 begin
5789 MRUText := MRUText + '+';
5790 end;
5791 MRUText := MRUText + FileName;
5792
5793 // stop after 50 chars
5794 if Length( MRUText ) > 50 then
5795 begin
5796 MRUText := MRUText + '+ ...';
5797 break;
5798 end;
5799 end;
5800 end;
5801
5802 MenuItem.Caption:= '~'
5803 + IntToStr( i + 1 )
5804 + '. '
5805 + MRUText;
5806 if MRUItem.Filenames.Count = 1 then
5807 MenuItem.Hint := MRUItem.Filenames[ 0 ]
5808 else
5809 MenuItem.Hint := MRUItem.Title
5810 + ' ('
5811 + IntToStr( MRUItem.Filenames.Count )
5812 + ' '
5813 + MRUMultipleFilesHint
5814 + ')';
5815
5816 MenuItem.OnClick:= OnMRUMenuItemClick;
5817 MenuItem.Tag:= i;
5818 FileMenu.Add( MenuItem );
5819 MRUMenuItems.Add( MenuItem );
5820 end;
5821end;
5822
5823procedure TMainForm.OnMRUMenuItemClick( Sender: TObject );
5824var
5825 Tag: longint;
5826 MenuItem: TMenuItem;
5827 MRUItem: TMRUItem;
5828begin
5829 MenuItem:= Sender as TMenuItem;
5830 Tag:= MenuItem.Tag;
5831 MRUItem := Settings.MRUList[ Tag ];
5832 if OpenFiles( MRUItem.FileNames, '', true ) then
5833 begin
5834 ClearHelpManager;
5835 end;
5836end;
5837
5838Procedure TMainForm.OnNavigateToMenuItemClick( Sender: TObject );
5839var
5840 MenuItem: TMenuItem;
5841 Tag: longint;
5842begin
5843 MenuItem:= Sender as TMenuItem;
5844 Tag:= MenuItem.Tag;
5845 NavigateToHistoryIndex( Tag );
5846end;
5847
5848Procedure TMainForm.AddChildNodes( HelpFile: THelpFile;
5849 ParentNode: TNode;
5850 Level: longint;
5851 Var TopicIndex: longint );
5852var
5853 Topic: TTopic;
5854 Node: TNode;
5855begin
5856 assert( ParentNode <> nil );
5857 Node := nil;
5858 while TopicIndex < HelpFile.TopicCount do
5859 begin
5860 Topic:= HelpFile.Topics[ TopicIndex ];
5861
5862 if Topic.ShowInContents then
5863 begin
5864 if Topic.ContentsLevel < Level then
5865 break;
5866
5867 if Topic.ContentsLevel = Level then
5868 begin
5869 Node:= ParentNode.AddChild( Topic.Title,
5870 Topic );
5871 inc( TopicIndex );
5872 end
5873 else
5874 begin
5875 assert( Node <> nil );
5876 AddChildNodes( HelpFile,
5877 Node,
5878 Topic.ContentsLevel,
5879 TopicIndex );
5880 Node := nil;
5881 end
5882 end
5883 else
5884 begin
5885 inc( TopicIndex );
5886 end;
5887 end;
5888
5889end;
5890
5891Procedure TMainForm.LoadContents( Files: TList;
5892 Var FirstNode: TNode );
5893var
5894 TopicIndex: longint;
5895 Topic: TTopic;
5896 Node: TNode;
5897 FileIndex: longint;
5898 HelpFile: THelpFile;
5899begin
5900 ContentsOutline.BeginUpdate;
5901 LogEvent(LogStartup, 'Load contents outline');
5902
5903 // we don't clear it first, to allow adding additional files
5904 // into the contents tree
5905
5906 LogEvent(LogStartup, 'Loop files');
5907
5908 FirstNode := nil;
5909
5910 Node := nil;
5911
5912 for FileIndex:= 0 to Files.Count - 1 do
5913 begin
5914 HelpFile := Files[ FileIndex ];
5915 LogEvent(LogStartup, 'File ' + IntToStr( FileIndex ) );
5916 TopicIndex := 0;
5917 while TopicIndex < HelpFile.TopicCount do
5918 begin
5919 Topic := HelpFile.Topics[ TopicIndex ];
5920 assert( Topic.ContentsLevel >= 0,
5921 'Topic contents level is ' + IntToStr( Topic.ContentsLevel ) );
5922 if Topic.ShowInContents then
5923 begin
5924 if Topic.ContentsLevel = 1 then
5925 begin
5926 Node := ContentsOutline.AddChild( Topic.Title,
5927 Topic );
5928 if FirstNode = nil then
5929 FirstNode := node;
5930
5931 inc( TopicIndex );
5932 end
5933 else
5934 begin
5935 // subnodes
5936 // ignore child nodes before the first root node
5937 // the org viewer does the same
5938 if Node = nil then
5939 begin
5940 inc( TopicIndex );
5941 end
5942 else
5943 begin
5944 AddChildNodes( HelpFile, Node, Topic.ContentsLevel, TopicIndex );
5945 Node := nil;
5946 end;
5947 end;
5948 end
5949 else
5950 begin
5951 inc( TopicIndex );
5952 end;
5953 end;
5954 end;
5955 LogEvent(LogStartup, ' EndUpdate' );
5956 ContentsOutline.EndUpdate;
5957
5958 if Settings.OpenWithExpandedContents then
5959 begin
5960 LogEvent(LogStartup, ' Expand all contents' );
5961 ContentsOutline.ExpandAll
5962 end
5963 else if ContentsOutline.ChildCount = 1 then
5964 begin
5965 LogEvent(LogStartup, ' Expand first node' );
5966 // Contents has only one top level node... expand it
5967 FirstNode.Expand;
5968 end;
5969
5970 ContentsLoaded := true;
5971 LogEvent(LogStartup, ' Contents loaded' );
5972
5973end;
5974
5975Procedure TMainForm.SaveNotesForFile( HelpFile: THelpFile );
5976var
5977 NotesFileName: string;
5978 TopicIndex: longword;
5979 Note: THelpNote;
5980 NoteIndex: longint;
5981
5982 NotesFile: HFile;
5983 OpenAction: ULong;
5984 rc: APIRET;
5985 CName: Cstring;
5986 FileNoteCount: integer;
5987
5988begin
5989 LogEvent(LogStartup, 'Save notes for ' + HelpFile.Filename );
5990
5991 if not HelpFile.NotesLoaded then
5992 // we never loaded the notes/displayed a topic from this file
5993 // so don't do anything.
5994 exit;
5995
5996 LogEvent(LogStartup, 'Really saving' );
5997
5998 NotesFileName := ChangeFileExt( HelpFile.FileName, '.nte' );
5999
6000 FileNoteCount := 0;
6001 for NoteIndex := 0 to Notes.Count - 1 do
6002 begin
6003 Note := Notes[ NoteIndex ];
6004
6005 if Note.Topic.HelpFile = HelpFile then
6006 inc( FileNoteCount );
6007 end;
6008
6009 if FileNoteCount = 0 then
6010 begin
6011 // no notes. delete notes file if it already exists.
6012 if FileExists( NotesFileName ) then
6013 DeleteFile( NotesFileName );
6014 exit;
6015 end;
6016
6017 CName:= NotesFileName;
6018 rc:= DosOpen( CName,
6019 NotesFile,
6020 OpenAction,
6021 0, // file size
6022 0, // attrs
6023 OPEN_ACTION_CREATE_IF_NEW + OPEN_ACTION_REPLACE_IF_EXISTS,
6024 OPEN_SHARE_DENYREADWRITE + OPEN_ACCESS_WRITEONLY,
6025 nil ); // no eas
6026 if rc <> 0 then
6027 begin
6028 DoErrorDlg( SaveNotesTitle,
6029 SaveNotesError
6030 + StrCRLF
6031 + NotesFileName
6032 + StrCRLF
6033 + SysErrorMessage( rc ) );
6034 exit;
6035 end;
6036
6037 for NoteIndex:= 0 to Notes.Count - 1 do
6038 begin
6039 Note:= Notes[ NoteIndex ];
6040
6041 if Note.Topic.HelpFile <> HelpFile then
6042 continue;
6043
6044 TopicIndex:= HelpFile.IndexOfTopic( Note.Topic );
6045
6046 MyWriteLn( NotesFile,
6047 IntToStr( TopicIndex ));
6048 MyWriteLn( NotesFile,
6049 IntToStr( Note.InsertPoint ) );
6050
6051 MyWrite( NotesFile,
6052 Note.Text.AsPChar,
6053 Note.Text.Length );
6054
6055 MyWriteLn( NotesFile,
6056 '' );
6057 MyWriteLn( NotesFile,
6058 '#ENDNOTE#' );
6059
6060 end;
6061
6062 DosClose( NotesFile );
6063end;
6064
6065Procedure TMainForm.LoadNotes( HelpFile: THelpFile );
6066var
6067 NotesFileName: string;
6068 TopicIndex: longint;
6069 InsertPoint: longint;
6070 Note: THelpNote;
6071
6072 NotesFile: HFile;
6073 OpenAction: ULong;
6074 rc: APIRET;
6075 CName: Cstring;
6076
6077 Paragraph: TAString;
6078 NotEOF: boolean;
6079 NoteText: TAString;
6080
6081begin
6082 LogEvent(LogStartup, 'Load notes for ' + HelpFile.Filename );
6083
6084 if HelpFile.NotesLoaded then
6085 exit;
6086
6087 HelpFile.NotesLoaded := true;
6088 NotesFileName := ChangeFileExt( HelpFile.FileName, '.nte' );
6089
6090 if not FileExists( NotesFileName ) then
6091 // no notes
6092 exit;
6093
6094 CName := NotesFileName;
6095 rc := DosOpen( CName,
6096 NotesFile,
6097 OpenAction,
6098 0, // file size - irrelevant, not creating,
6099 0, // attrs - ''
6100 OPEN_ACTION_OPEN_IF_EXISTS,
6101 OPEN_SHARE_DENYREADWRITE + OPEN_ACCESS_READONLY,
6102 nil ); // no eas
6103 if rc <> 0 then
6104 begin
6105 DoErrorDlg( LoadNotesTitle,
6106 LoadNotesError
6107 + StrCRLF
6108 + NotesFileName
6109 + StrCRLF
6110 + SysErrorMessage( rc ) );
6111 exit;
6112 end;
6113
6114 Paragraph := TAString.Create;
6115 NoteText := TAString.Create;
6116
6117 NotEOF := true;
6118
6119 while NotEOF do
6120 begin
6121 // Read contents index
6122 NotEOF := Paragraph.ReadParagraph( NotesFile );
6123 if not NotEOF then
6124 continue;
6125 try
6126 TopicIndex := StrToInt( Paragraph.AsString );
6127 except
6128 TopicIndex := -1;
6129 end;
6130
6131 // Read insert point
6132 NotEOF := Paragraph.ReadParagraph( NotesFile );
6133 if not NotEOF then
6134 continue;
6135 try
6136 InsertPoint := StrToInt( Paragraph.AsString );
6137 except
6138 InsertPoint := -1;
6139 end;
6140
6141 NoteText.Clear;
6142
6143 while NotEOF do
6144 begin
6145 NotEOF := Paragraph.ReadParagraph( NotesFile );
6146 if Paragraph.SameAs( '#ENDNOTE#' ) then
6147 begin
6148 // found end of note
6149 if ( TopicIndex >= 0 )
6150 and ( InsertPoint >= 0 ) then
6151 begin
6152 Note := THelpNote.Create;
6153 Note.Topic := HelpFile.Topics[ TopicIndex ];
6154 Note.InsertPoint := InsertPoint;
6155
6156 // Remove the last end line
6157 Note.Text.Assign( NoteText );
6158 if Note.Text.Length > 2 then
6159 Note.Text.Delete( Note.Text.Length - 2, 2 );
6160
6161 Notes.Add( Note );
6162 end;
6163 break;
6164 end;
6165 NoteText.Add( Paragraph );
6166 NoteText.AddString( #13 + #10 );
6167 end;
6168
6169 end;
6170 DosClose( NotesFile );
6171
6172 Paragraph.Destroy;
6173 NoteText.Destroy;
6174
6175end;
6176
6177Procedure TMainForm.UpdateNotesDisplay;
6178var
6179 NoteIndex: longint;
6180 Note: THelpNote;
6181 NoteTitle: string;
6182begin
6183 NotesListBox.Clear;
6184 for NoteIndex := 0 to Notes.Count - 1 do
6185 begin
6186 Note := Notes[ NoteIndex ];
6187
6188 if Note.Topic > nil then
6189 NoteTitle := Note.Topic.Title
6190 else
6191 NoteTitle := StrLeft( Note.Text.AsString, 100 );
6192 NotesListBox.Items.AddObject( NoteTitle,
6193 Note );
6194 end;
6195 EnableNotesControls;
6196end;
6197
6198Procedure TMainForm.EnableNotesControls;
6199var
6200 NoteSelected: boolean;
6201begin
6202 NoteSelected:= NotesListBox.ItemIndex <> -1;
6203 EditNoteButton.Enabled:= NoteSelected;
6204 GotoNoteButton.Enabled:= NoteSelected;
6205 DeleteNoteButton.Enabled:= NoteSelected;
6206 AddNoteButton.Enabled := CurrentOpenFiles.Count > 0;
6207end;
6208
6209Function TMainForm.OKToCloseFile: boolean;
6210begin
6211 Result := true;
6212
6213 if PrintThread = nil then
6214 // haven't used print thread yet
6215 exit;
6216
6217 if not PrintThread.IsRunning then
6218 // not currently running
6219 exit;
6220
6221 Result := DoConfirmDlg( CheckStopPrintTitle,
6222 CheckStopPrintMsg );
6223
6224end;
6225
6226Procedure TMainForm.StopPrinting;
6227begin
6228 if PrintThread <> nil then
6229 begin
6230 if PrintThread.IsRunning then
6231 begin
6232 SetStatus( StoppingPrintMsg );
6233 PrintThread.ForceStop( 5 ); // wait up to 5 seconds then terminate
6234 SetStatus( PrintStoppedMsg );
6235 ResetProgress;
6236 end;
6237 end;
6238end;
6239
6240Procedure TMainForm.CloseFile;
6241var
6242 FileIndex: longint;
6243 HelpFile: THelpFile;
6244 M1: longint;
6245begin
6246 StopPrinting;
6247
6248 LogEvent(LogShutdown, 'Set Caption' );
6249 MainTitle := '';
6250 SetMainCaption;
6251
6252 LogEvent(LogShutdown, 'Close Windows' );
6253 CloseWindows;
6254
6255 LogEvent(LogShutdown, 'Set selected node to nil' );
6256 ContentsOutline.SelectedNode:= Nil;
6257
6258 M1:= MemAvail;
6259
6260 LogEvent(LogShutdown, 'Clear contents outline' );
6261 ContentsOutline.Clear;
6262
6263 LogEvent(LogShutdown, 'Free contents: ' + IntToStr( MemAvail - M1 ) );
6264 M1:= MemAvail;
6265
6266 DisplayedIndex.Clear;
6267 IndexListBox.Clear;
6268 LogEvent(LogShutdown, 'Clear index ' + IntToStr( MemAvail - M1 ) );
6269 M1:= MemAvail;
6270
6271 NotesListBox.Clear;
6272 SearchResultsListBox.Clear;
6273
6274 LogEvent(LogShutdown, 'Notes, search etc ' + IntToStr( MemAvail - M1 ) );
6275 M1:= MemAvail;
6276
6277 // First save notes and bookmarks.
6278 // It's important we do this first
6279 // since we scan all notes each time to find the ones
6280 // belonging to this file.
6281 SaveBookmarks;
6282
6283 SaveNotes;
6284
6285 ClearAllWordSequences;
6286
6287 LogEvent(LogShutdown, 'Destroy helpfile objects' );
6288
6289 // Now destroy help files
6290 for FileIndex := 0 to CurrentOpenFiles.Count - 1 do
6291 begin
6292 HelpFile := CurrentOpenFiles[ FileIndex ];
6293 GlobalFilelist.RemoveFile( Frame.Handle,
6294 HelpFile.Filename );
6295 HelpFile.Free;
6296 end;
6297
6298 CurrentOpenFiles.Clear;
6299
6300 LogEvent(LogShutdown, 'Destroy helpfiles ' + IntToStr( MemAvail - M1 ) );
6301 M1 := MemAvail;
6302
6303 LogEvent(LogShutdown, 'Clear notes' );
6304 ClearNotes;
6305
6306 LogEvent(LogShutdown, 'Clear bookmarks' );
6307 ClearBookmarks;
6308
6309 ClearPageHistory;
6310
6311 LogEvent(LogShutdown, 'Enable controls' );
6312 EnableControls;
6313
6314 LogEvent(LogShutdown, 'CloseFile done' );
6315
6316end;
6317
6318Function TMainForm.FindOpenHelpFile( FileName: string ): THelpFile;
6319var
6320 FileIndex: longint;
6321begin
6322 for FileIndex:= 0 to CurrentOpenFiles.Count - 1 do
6323 begin
6324 Result:= CurrentOpenFiles[ FileIndex ];
6325 if StrEqualIgnoringCase( Result.Filename, FileName ) then
6326 // found
6327 exit;
6328 end;
6329 Result:= nil;
6330end;
6331
6332// This rather horrendous looking bit of code simply:
6333
6334// Gets the contents from each file
6335// Sorts it alphabetically.
6336// Merges all the sorted contents and indexes together,
6337// alphabetically.
6338type
6339 TListType = ( ltContents, ltIndex );
6340
6341procedure TMainForm.LoadIndex;
6342var
6343 HelpFile: THelpFile;
6344 TextCompareResult: integer;
6345
6346 FileIndex: longint;
6347
6348 Contents: TList;
6349 ContentsLists: TList; // of tlist
6350 IndexLists: TList; // of tstringlist
6351 ContentsNextIndex: array[ 0..255 ] of longint;
6352 IndexNextIndex: array[ 0..255 ] of longint;
6353 Topic: TTopic;
6354
6355 ListIndex: longint;
6356
6357 pListEntry: pstring;
6358 pLowestEntry: pstring;
6359 pLastEntry: pstring;
6360
6361 LowestEntryListIndex: longint;
6362 LowestEntryListType: TListType;
6363 LowestEntryTopic: TTopic;
6364
6365 Index: TStringList;
6366
6367 i : longint;
6368begin
6369 LogEvent(LogStartup, 'Create index' );
6370
6371 SetWaitCursor;
6372
6373 LogEvent(LogStartup, ' Get/sort lists' );
6374
6375 ProgressBar.Position := 70;
6376 SetStatus( 'Building index... ' );
6377
6378 ContentsLists := TList.Create;
6379 IndexLists := TList.Create;
6380
6381 // collect the contents and index lists from the files
6382 for FileIndex := 0 to CurrentOpenFiles.Count - 1 do
6383 begin
6384 HelpFile := CurrentOpenFiles[ FileIndex ];
6385 ProgressBar.Position := 70 + 10 * FileIndex div CurrentOpenFiles.Count;
6386
6387 if Settings.IndexStyle in [ isAlphabetical, isFull ] then
6388 begin
6389 Contents := TList.Create;
6390 Contents.Capacity := HelpFile.TopicCount;
6391
6392 // copy [contents] topic list
6393 for i := 0 to HelpFile.TopicCount - 1 do
6394 begin
6395 Topic := HelpFile.Topics[ i ];
6396 if Topic.ShowInContents then
6397 Contents.Add( Topic );
6398 end;
6399
6400 // sort by title
6401 Contents.Sort( TopicTitleCompare );
6402
6403 ContentsLists.Add( Contents );
6404
6405 // initialise list index
6406 ContentsNextIndex[ ContentsLists.Count - 1 ] := 0;
6407 end;
6408
6409 if Settings.IndexStyle in [ isFileOnly, isFull ] then
6410 begin
6411 IndexLists.Add( HelpFile.Index );
6412 IndexNextIndex[ IndexLists.Count - 1 ] := 0;
6413 end;
6414 end;
6415
6416 // Unlike contents, we do clear the index
6417 // (even if we are adding more files) because we need
6418 // to re-merge the whole thing
6419 DisplayedIndex.Clear;
6420 ProgressBar.Position := 80;
6421
6422 LogEvent(LogStartup, ' Merge lists' );
6423
6424 pLastEntry := NullStr;
6425 while true do
6426 begin
6427 pLowestEntry := NullStr;
6428 LowestEntryListIndex := -1;
6429
6430 // Find alphabetically lowest (remaining) topic
6431
6432 // first, look in contents lists
6433 for ListIndex := 0 to ContentsLists.Count - 1 do
6434 begin
6435 Contents := ContentsLists[ ListIndex ];
6436 if ContentsNextIndex[ ListIndex ] < Contents.Count then
6437 begin
6438 // list is not yet finished, get next entry
6439 Topic := Contents[ ContentsNextIndex[ ListIndex ] ];
6440 pListEntry := Topic.TitlePtr;
6441
6442 if pLowestEntry^ <> '' then
6443 TextCompareResult := CompareText( pListEntry^, pLowestEntry^ )
6444 else
6445 TextCompareResult := -1;
6446
6447 if TextCompareResult < 0 then
6448 begin
6449 // this index entry comes before the lowest one so far
6450 pLowestEntry := pListEntry;
6451 LowestEntryListIndex := ListIndex;
6452 LowestEntryListType := ltContents;
6453 LowestEntryTopic := Topic;
6454 end;
6455 end;
6456 end;
6457
6458 // look in indices
6459 for ListIndex := 0 to IndexLists.Count - 1 do
6460 begin
6461 Index := IndexLists[ ListIndex ];
6462 if IndexNextIndex[ ListIndex ] < Index.Count then
6463 begin
6464 // list is not yet finished, get next entry
6465 pListEntry := Index.ValuePtrs[ IndexNextIndex[ ListIndex ] ];
6466
6467 if pLowestEntry^ <> '' then
6468 TextCompareResult := CompareText( pListEntry^, pLowestEntry^ )
6469 else
6470 TextCompareResult := -1;
6471
6472 if TextCompareResult < 0 then
6473 begin
6474 // this index entry comes before the lowest one so far
6475 pLowestEntry := pListEntry;
6476 LowestEntryListIndex := ListIndex;
6477 LowestEntryListType := ltIndex;
6478 LowestEntryTopic := TTopic( Index.Objects[ IndexNextIndex[ ListIndex ] ] );
6479 end;
6480 end;
6481 end;
6482
6483 if LowestEntryListIndex = -1 then
6484 // we're out
6485 break;
6486
6487 if ( pLowestEntry^ ) <> ( pLastEntry^ ) then
6488 // add, if different from last
6489 DisplayedIndex.AddObject( pLowestEntry^,
6490 LowestEntryTopic );
6491 pLastEntry := pLowestEntry;
6492
6493 if LowestEntryListType = ltContents then
6494 begin
6495 inc( ContentsNextIndex[ LowestEntryListIndex ] );
6496 end
6497 else
6498 begin
6499 // found in one of indices.
6500 // Check for subsequent indented strings
6501 Index := IndexLists[ LowestEntryListIndex ];
6502
6503 i := IndexNextIndex[ LowestEntryListIndex ] + 1;
6504 while i < Index.Count do
6505 begin
6506 pListEntry := Index.ValuePtrs[ i ];
6507 if pListEntry^ = '' then
6508 break;
6509
6510 if pListEntry^[ 1 ] <> ' ' then
6511 // not indented, stop looking
6512 break;
6513
6514 // found one,
6515 Topic := Index.Objects[ i ] as TTopic;
6516 DisplayedIndex.AddObject( pListEntry^,
6517 Topic );
6518 inc( i );
6519 end;
6520 IndexNextIndex[ LowestEntryListIndex ] := i;
6521 end;
6522 end;
6523
6524 ProgressBar.Position := 95;
6525 LogEvent(LogStartup, ' Display index (count = '
6526 + IntToStr( DisplayedIndex.Count )
6527 + ')' );
6528
6529 // Now display the final index list
6530 IndexListBox.Items.Assign( DisplayedIndex );
6531
6532 LogEvent(LogStartup, ' Tidy up' );
6533
6534 IndexLists.Destroy;
6535
6536 DestroyListAndObjects( ContentsLists );
6537
6538 IndexLoaded := true;
6539
6540 ClearWaitCursor;
6541
6542 SetStatus( 'Index loaded' );
6543 LogEvent(LogStartup, ' Done' );
6544end;
6545
6546Procedure TMainForm.OnHelpFileLoadProgress( n, outof: integer;
6547 message: string );
6548var
6549 ProgressOnFiles: longint;
6550 Filename: string;
6551 ProgressOnThisFile: longint;
6552
6553begin
6554 Filename := LoadingFilenameList[ LoadingFileIndex ];
6555
6556 ProgressOnFiles := round( 100 * LoadingFileIndex / LoadingFilenameList.Count );
6557 ProgressOnThisFile := round( 100 * n / outof / LoadingFilenameList.Count );
6558
6559 SetProgress( ( ProgressOnFiles + ProgressOnThisFile ) div 2,
6560 100,
6561 LoadingFileMsg
6562 + ExtractFileName( Filename )
6563 + ': '
6564 + message );
6565end;
6566
6567Procedure TMainForm.SetProgress( n, outof: integer;
6568 message: string );
6569begin
6570 ProgressBar.Position := n * 100 div outof;
6571 SetStatus( message );
6572 ProgressBar.Show;
6573end;
6574
6575// Load a single file.
6576Function TMainForm.OpenFile( const FileName: string;
6577 const WindowTitle: string;
6578 const SelectFirstContentsNode: boolean ): boolean;
6579var
6580 FileNames: TStringList;
6581begin
6582 FileNames := TStringList.Create;
6583 FileNames.Add( FileName );
6584 Result := OpenFiles( FileNames,
6585 WindowTitle,
6586 DisplayFirstTopic );
6587 FileNames.Destroy;
6588end;
6589
6590Function TMainForm.OpenAdditionalFile( const FileName: string;
6591 const DisplayFirstTopic: boolean ): boolean;
6592var
6593 FileNames: TStringList;
6594begin
6595 FileNames := TStringList.Create;
6596 FileNames.Add( FileName );
6597 Result := OpenAdditionalFiles( FileNames,
6598 DisplayFirstTopic );
6599 FileNames.Destroy;
6600end;
6601
6602Function TMainForm.OpenWindowsHelp( const Filename: string ): boolean;
6603var
6604 WinHelpDetails: PROGDETAILS;
6605 szFilename: cstring;
6606begin
6607
6608 result := true;
6609 if Settings.ConfirmWinHelp then
6610 result := DoYesNoDlg( WindowsHelpTitle,
6611 WindowsHelpPrompt
6612 + StrCRLF
6613 + FileName );
6614 if not result then
6615 exit;
6616
6617 szFilename := FileName;
6618 with WinHelpDetails do
6619 begin
6620 Length := sizeof( WinHelpDetails );
6621 progt.progc := PROG_31_ENHSEAMLESSCOMMON ;
6622 progt.fbVisible := SHE_VISIBLE;
6623 pszTitle := ''; // not used?
6624 pszExecutable := 'winhelp.exe';
6625 pszParameters := Addr( szFilename );
6626 pszStartupDir := nil;
6627 pszIcon := nil;
6628 pszEnvironment := nil;
6629 swpInitial.fl := SWP_ACTIVATE or SWP_SHOW;
6630 end;
6631
6632 result := WinStartApp( NULLHANDLE,
6633 WinHelpDetails,
6634 '',
6635 nil,
6636 SAF_INSTALLEDCMDLINE ) <> 0;
6637
6638 // Doesn't work for Dos/Win programs
6639 // RunProgram( 'winhelp.exe', FileName );
6640end;
6641
6642// Load the specified set of help files
6643Function TMainForm.LoadFiles( const FileNames: TStrings;
6644 HelpFiles: TList ): boolean;
6645var
6646 HelpFile: THelpFile;
6647 FileIndex: longint;
6648 FileName: string;
6649 FullFilePath: string;
6650
6651 FileHandlesAdjustNum: LONG;
6652 CurrentMaxFileHandles: ULONG;
6653 RequiredFileHandles: LONG;
6654begin
6655 LogEvent(LogStartup, 'LoadFiles' );
6656
6657 LoadingFilenameList := TStringList.Create;
6658
6659 TranslateIPFEnvironmentVars( FileNames, LoadingFilenameList );
6660
6661 LogEvent(LogStartup, 'Finding files' );
6662
6663 ProgressBar.Show;
6664
6665 // now find full file paths,
6666 // and also the total file size for progress display
6667 for FileIndex := 0 to LoadingFilenameList.Count - 1 do
6668 begin
6669 FileName := LoadingFilenameList[ FileIndex ];
6670 LogEvent(LogStartup, ' File: ' + FileName );
6671
6672 // Find the help file, if possible
6673 if Filename = OWN_HELP_MARKER then
6674 begin
6675 FullFilePath := CmdLineParameters.GetOwnHelpFileName;
6676 end
6677 else
6678 begin
6679 FullFilePath := FindHelpFile( Filename );
6680 end;
6681
6682 if FullFilePath <> '' then
6683 begin
6684 LogEvent(LogStartup, ' Full path: ' + FullFilePath );
6685 end
6686 else
6687 begin
6688 LogEvent(LogStartup, ' File not found' );
6689 FullFilePath := FileName; // we'll complain later.
6690 end;
6691 LoadingFilenameList[ FileIndex ] := FullFilePath;
6692 end;
6693
6694 // Make sure we have enough file handles
6695
6696 FileHandlesAdjustNum := 0;
6697 DosSetRelMaxFH( FileHandlesAdjustNum, // 0 queries current
6698 CurrentMaxFileHandles );
6699
6700 RequiredFileHandles := CurrentOpenFiles.Count // already opened
6701 + LoadingFilenameList.Count // new ones
6702 + 40; // some spares.
6703 if CurrentMaxFileHandles < RequiredFileHandles then
6704 begin
6705 // need some more
6706 FileHandlesAdjustNum := RequiredFileHandles - CurrentMaxFileHandles;
6707 DosSetRelMaxFH( FileHandlesAdjustNum,
6708 CurrentMaxFileHandles );
6709 end;
6710
6711 // Now actually load the files
6712 for FileIndex := 0 to LoadingFilenameList.Count - 1 do
6713 begin
6714 Filename := LoadingFilenameList[ FileIndex ];
6715 LogEvent(LogStartup, ' Loading: ' + Filename );
6716 try
6717 LoadingFileIndex := FileIndex;
6718
6719 // load the file
6720 HelpFile := THelpFile.Create( FileName );
6721 if Settings.FixedFontSubstitution then
6722 HelpFile.SetupFontSubstitutes( Settings.FixedFontSubstitutes );
6723
6724 HelpFiles.Add( HelpFile );
6725
6726 except
6727 on E: Exception do
6728 begin
6729
6730 if E is EWindowsHelpFormatException then
6731 begin
6732 OpenWindowsHelp( Filename );
6733 end
6734 else
6735 begin
6736 DoErrorDlg( FileOpenTitle,
6737 HelpFileError
6738 + FileName
6739 + ': '
6740 + E.Message );
6741 end;
6742
6743 // back out of the load process
6744 Result := false;
6745
6746 DestroyListObjects( HelpFiles );
6747
6748 LoadingFilenameList.Destroy;
6749 ResetProgress;
6750 exit;
6751 end
6752 end;
6753 end;
6754
6755 LoadingFilenameList.Destroy;
6756
6757 Result := true;
6758
6759end;
6760
6761// Add the current list of open files as
6762// a Most Recently Used entry
6763Procedure TMainForm.AddCurrentToMRUFiles;
6764var
6765 Filenames: TStringList;
6766 i: longint;
6767 HelpFile: THelpFile;
6768begin
6769 Filenames := TStringList.Create;
6770
6771 for i := 0 to CurrentOpenFiles.Count - 1 do
6772 begin
6773 HelpFile := CurrentOpenFiles[ i ];
6774 Filenames.Add( HelpFile.Filename );
6775 end;
6776
6777 // update most-recently-used file list
6778 HelpFile := CurrentOpenFiles[ 0 ];
6779 AddToMRUList( HelpFile.Title,
6780 Filenames );
6781
6782 // recreate menu
6783 CreateMRUMenuItems;
6784
6785 Filenames.Destroy;
6786end;
6787
6788// Display the specified set of files
6789Procedure TMainForm.DisplayFiles( NewFiles: TList;
6790 Var FirstContentsNode: TNode );
6791var
6792 HelpFile: THelpFile;
6793 FileIndex: longint;
6794begin
6795 LogEvent(LogStartup, 'DisplayFiles' );
6796 // Now load the various parts of the file(s)
6797 // into the user interface
6798 ProgressBar.Position := 50;
6799 SetStatus( LoadingStatusDisplaying );
6800
6801 // Add our open files in the global filelist
6802 for FileIndex := 0 to NewFiles.Count - 1 do
6803 begin
6804 HelpFile := NewFiles[ FileIndex ];
6805 GlobalFilelist.AddFile( HelpFile.Filename, Frame.Handle );
6806 // LoadNotes( HelpFile );
6807 LoadBookmarks( HelpFile );
6808 end;
6809
6810 UpdateNotesDisplay;
6811
6812 BuildBookmarksMenu;
6813 UpdateBookmarksForm;
6814
6815 ProgressBar.Position := 55;
6816
6817 ContentsLoaded := false;
6818 IndexLoaded := false;
6819
6820 LoadContents( NewFiles, FirstContentsNode );
6821
6822 ProgressBar.Position := 75;
6823
6824 // LoadIndex;
6825
6826 ProgressBar.Position := 100;
6827 SetStatus( LoadingStatusDone );
6828
6829 LogEvent(LogStartup, 'DisplayFiles Done' );
6830
6831end;
6832
6833Function TMainForm.OpenFiles( const FileNames: TStrings;
6834 const WindowTitle: string;
6835 const DisplayFirstTopic: boolean ): boolean;
6836var
6837 HelpFiles: TList;
6838 FirstContentsNode: TNode;
6839begin
6840 LogEvent(LogStartup, 'OpenFiles' );
6841
6842 if not OKToCloseFile then
6843 exit;
6844
6845 SetWaitCursor;
6846
6847 HelpFiles := TList.Create;
6848
6849 if not LoadFiles( FileNames,
6850 HelpFiles ) then
6851 begin
6852 ClearWaitCursor;
6853 HelpFiles.Destroy;
6854 exit;
6855 end;
6856
6857 Result := true;
6858
6859 SearchResultsListBox.Clear;
6860 PageHistory.Clear;
6861 CurrentHistoryIndex := -1;
6862
6863 // Now that we have successfully loaded the new help file(s)
6864 // close the existing one.
6865 CloseFile;
6866
6867 AssignList( HelpFiles, CurrentOpenFiles );
6868
6869 ProgressBar.Position := 50;
6870 SetStatus( LoadingStatusDisplaying );
6871
6872 AddCurrentToMRUFiles;
6873
6874 if WindowTitle = '' then
6875 MainTitle := THelpFile( CurrentOpenFiles[ 0 ] ).Title
6876 else
6877 MainTitle := WindowTitle;
6878
6879 SetMainCaption;
6880
6881 // Now load the various parts of the file(s)
6882 // into the user interface
6883
6884 ContentsOutline.Clear;
6885
6886 DisplayFiles( HelpFiles,
6887 FirstContentsNode );
6888
6889 if CmdLineParameters.getHelpManagerFlag then
6890 ShowLeftPanel := Settings.ShowLeftPanel_Help
6891 else
6892 ShowLeftPanel := Settings.ShowLeftPanel_Standalone;
6893
6894 // Select first contents node if there is one
6895 if FirstContentsNode <> nil then
6896 begin
6897 LogEvent(LogStartup, ' Select first node' );
6898 ContentsOutline.SelectedNode := FirstContentsNode;
6899 end;
6900
6901 ClearWaitCursor;
6902
6903 ResetProgress;
6904
6905 NotebookOnPageChanged( self ); // ensure e.g. index loaded
6906
6907 EnableControls;
6908
6909 if DisplayFirstTopic then
6910 begin
6911 LogEvent(LogStartup, 'Display first topic' );
6912 DisplaySelectedContentsTopic;
6913 end;
6914
6915 LogEvent(LogStartup, 'OpenFiles complete' );
6916end;
6917
6918Function TMainForm.OpenAdditionalFiles( const FileNames: TStrings;
6919 const DisplayFirstTopic: boolean ): boolean;
6920var
6921 HelpFiles: TList;
6922 FirstNewContentsNode: TNode;
6923begin
6924 LogEvent(LogStartup, 'OpenAdditionalFiles' );
6925
6926 if not OKToCloseFile then
6927 exit;
6928
6929 SetWaitCursor;
6930
6931 HelpFiles := TList.Create;
6932
6933 if not LoadFiles( FileNames,
6934 HelpFiles ) then
6935 begin
6936 ClearWaitCursor;
6937 HelpFiles.Destroy;
6938 exit;
6939 end;
6940
6941 Result := true;
6942
6943 AddList( HelpFiles, CurrentOpenFiles );
6944
6945 AddCurrentToMRUFiles;
6946
6947 DisplayFiles( HelpFiles,
6948 FirstNewContentsNode );
6949
6950 // Select first contents node of new file
6951 if FirstNewContentsNode <> nil then
6952 ContentsOutline.SelectedNode := FirstNewContentsNode;
6953
6954 HelpFiles.Destroy;
6955
6956 ClearWaitCursor;
6957
6958 ResetProgress;
6959
6960 EnableControls;
6961
6962 if DisplayFirstTopic then
6963 DisplaySelectedContentsTopic;
6964
6965 LogEvent(LogStartup, 'OpenAdditionalFiles complete' );
6966end;
6967
6968Procedure TMainForm.OpenMIOnClick (Sender: TObject);
6969Begin
6970 FileOpen;
6971end;
6972
6973procedure TMainForm.FileOpen;
6974var
6975 Filenames: TStringList;
6976 KeepCurrentFiles: boolean;
6977 OpenedOK: boolean;
6978begin
6979 if not OKToCloseFile then
6980 exit;
6981
6982 if Settings.UseOriginalDialogs then
6983 begin
6984 SystemOpenDialog.Filename := AddDirectorySeparator( Settings.LastOpenDirectory ) + '*.hlp;*.inf';
6985 if not SystemOpenDialog.Execute then
6986 exit;
6987
6988 Settings.LastOpenDirectory := ExtractFilePath( SystemOpenDialog.Filename );
6989 // note - sibyl's encapsulation doesn't allow multi-select
6990 OpenedOK := OpenFile( SystemOpenDialog.FileName, '', true );
6991 end
6992 else
6993 begin
6994 Filenames := TStringList.Create;
6995 KeepCurrentFiles := false;
6996 if not DoOpenMultiFileDialog( FileOpenTitle,
6997 HelpFilesDesc
6998 + '|*.inf;*.hlp|'
6999 + AllFilesDesc
7000 + '|*.*',
7001 '*.hlp;*.inf',
7002 Settings.LastOpenDirectory,
7003 KeepCurrentFiles,
7004 Filenames ) then
7005 exit;
7006
7007 if KeepCurrentFiles then
7008 OpenedOK := OpenAdditionalFiles( FileNames, true )
7009 else
7010 OpenedOK := OpenFiles( FileNames, '', true );
7011 Filenames.Destroy;
7012 end;
7013
7014 if OpenedOK then
7015 ClearHelpManager;
7016End;
7017
7018Procedure TMainForm.CloseWindows;
7019Begin
7020 DestroyListObjects( Windows );
7021 Windows.Clear;
7022end;
7023
7024// Help manager mode
7025
7026// if window is minimised then restore it
7027// (ideally should go back to maximized - don't know how)
7028Procedure TMainForm.RestoreWindow;
7029Begin
7030 If WindowState = wsMinimized then
7031 WindowState := wsNormal;
7032end;
7033
7034
7035Procedure TMainForm.NHMDisplayIndex( Var Msg: TMessage );
7036begin
7037 LogEvent(LogNHM, 'NHMDisplayIndex');
7038 CmdLineParameters.addNhmDebugMessage('NHMDisplayIndex');
7039 RestoreWindow;
7040 DisplayIndex;
7041 // if nothing is being display already...
7042 if Windows.Count = 0 then
7043 // display first topic
7044 DisplaySelectedContentsTopic;
7045end;
7046
7047Procedure TMainForm.NHMDisplayContents( Var Msg: TMessage );
7048begin
7049 LogEvent(LogNHM, 'NHMDisplayContents');
7050 CmdLineParameters.addNhmDebugMessage('NHMDisplayContents');
7051 RestoreWindow;
7052 DisplayContents;
7053 // if nothing is being display already...
7054 if Windows.Count = 0 then
7055 begin
7056 // display first topic
7057 DisplaySelectedContentsTopic;
7058 end;
7059end;
7060
7061Procedure TMainForm.NHMTopicByResourceID( Var Msg: TMessage );
7062begin
7063 LogEvent(LogNHM, 'NHMTopicByResourceID');
7064 RestoreWindow;
7065 if ShowLeftPanel then
7066 begin
7067 DisplayContents;
7068 end;
7069 CmdLineParameters.addNhmDebugMessage('NHMTopicByResourceID ' + IntToStr(Msg.Param1));
7070 DisplayTopicByResourceID( Msg.Param1 );
7071end;
7072
7073Procedure TMainForm.NHMTopicByPanelName( Var Msg: TMessage );
7074var
7075 pMessageMem: pchar;
7076 PanelName: string;
7077 Topic: TTopic;
7078begin
7079 LogEvent(LogNHM, 'NHMTopicByPanelName');
7080 RestoreWindow;
7081 if ShowLeftPanel then
7082 DisplayContents;
7083
7084 pMessageMem := pchar( Msg.Param1 );
7085 PanelName := StrPas( pMessageMem );
7086 SharedMemory.Free( pMessageMem );
7087
7088 LogEvent(LogNHM, '....NHMTopicByPanelName panel:' + PanelName);
7089 CmdLineParameters.addNhmDebugMessage('NHMTopicByPanelName ' + PanelName);
7090 Topic := FindTopicByName( PanelName );
7091 if Topic = nil then
7092 Topic := FindTopicByGlobalName( PanelName );
7093
7094 if Topic <> nil then
7095 DisplayTopic( Topic )
7096 else
7097 SearchFor( PanelName );
7098end;
7099
7100// Sent from other instances starting up (and exiting immediately)
7101
7102Procedure TMainForm.NHMSearch( Var Msg: TMessage );
7103var
7104 pSearchText: pchar;
7105 tmpSearchText : String;
7106begin
7107 LogEvent(LogNHM, 'NHMSearch');
7108 RestoreWindow;
7109
7110 pSearchText := pstring( Msg.Param1 );
7111 tmpSearchText := StrPas(pSearchText);
7112 CmdLineParameters.addNhmDebugMessage('NHMSearch ' + tmpSearchText);
7113 SearchFor(tmpSearchText);
7114 SharedMemory.Free( pSearchText );
7115end;
7116
7117Procedure TMainForm.NHMGlobalSearch( Var Msg: TMessage );
7118var
7119 pSearchText: pchar;
7120 tmpSearchText : String;
7121begin
7122 LogEvent(LogNHM, 'NHMGlobalSearch');
7123 RestoreWindow;
7124
7125 pSearchText := pstring( Msg.Param1 );
7126 tmpSearchText := StrPas(pSearchText);
7127 CmdLineParameters.addNhmDebugMessage('NHMGlobalSearch ' + tmpSearchText);
7128 DoGlobalSearch(tmpSearchText);
7129 SharedMemory.Free( pSearchText );
7130end;
7131
7132Procedure TMainForm.NHMShowUsage( Var Msg: TMessage );
7133begin
7134 LogEvent(LogNHM, 'NHMShowUsage');
7135 CmdLineParameters.addNhmDebugMessage('NHMShowUsage');
7136 RestoreWindow;
7137 ShowUsage;
7138end;
7139
7140Procedure TMainForm.NHMSetFiles( Var Msg: TMessage );
7141var
7142 pFileNames: pchar;
7143 tmpFileNames : String;
7144begin
7145 LogEvent(LogNHM, 'NHMSetFiles');
7146
7147 // NOT restoring window here because this is not something the user should see...
7148 pFileNames := pstring( Msg.Param1 );
7149 tmpFileNames := StrPas(pFileNames);
7150 CmdLineParameters.addNhmDebugMessage('NHMSetFiles ' + tmpFileNames);
7151 OpenFilesFromTextList(tmpFileNames, false);
7152 SharedMemory.Free( pFileNames );
7153end;
7154
7155Procedure TMainForm.NHMSetTitle( Var Msg: TMessage );
7156var
7157 pTitle: pchar;
7158begin
7159 LogEvent(LogNHM, 'NHMSetTitle');
7160
7161 pTitle := pstring( Msg.Param1 );
7162 MainTitle := StrPas( pTitle );
7163 SharedMemory.Free( pTitle );
7164 CmdLineParameters.addNhmDebugMessage('NHMSetTitle ' + MainTitle);
7165 SetMainCaption;
7166end;
7167
7168Procedure TMainForm.NHMTest( Var Msg: TMessage );
7169var
7170 ps: pstring;
7171begin
7172 LogEvent(LogNHM, 'NHMTest');
7173 ps := PString( Msg.Param1 );
7174 ShowMessage( 'Got test message: ' + ps^ );
7175 SharedMemory.Free( ps );
7176end;
7177
7178Initialization
7179 RegisterClasses ([TMainForm, TSplitBar,
7180 TNoteBook,
7181 TEdit, TListBox,
7182 TRichTextView, TCoolBar2, TMainMenu, TMenuItem,
7183 TImageList, TPanel, TButton,
7184 TSystemOpenDialog, TOutline2, TCustomListBox, TPopupMenu, TSpeedButton
7185 , TProgressBar, TTabSet2]);
7186End.
Note: See TracBrowser for help on using the repository browser.