chmsitemap.pas 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864
  1. { Copyright (C) <2005> <Andrew Haines> chmsitemap.pas
  2. This library is free software; you can redistribute it and/or modify it
  3. under the terms of the GNU Library General Public License as published by
  4. the Free Software Foundation; either version 2 of the License, or (at your
  5. option) any later version.
  6. This program is distributed in the hope that it will be useful, but WITHOUT
  7. ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  8. FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License
  9. for more details.
  10. You should have received a copy of the GNU Library General Public License
  11. along with this library; if not, write to the Free Software Foundation,
  12. Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  13. }
  14. {
  15. See the file COPYING.FPC, included in this distribution,
  16. for details about the copyright.
  17. }
  18. {$IFNDEF FPC_DOTTEDUNITS}
  19. unit chmsitemap;
  20. {$ENDIF FPC_DOTTEDUNITS}
  21. {$mode Delphi}{$H+}
  22. {define preferlower}
  23. interface
  24. {$IFDEF FPC_DOTTEDUNITS}
  25. uses
  26. System.Classes, System.SysUtils, Fcl.FastHtmlParser, System.Contnrs, System.StrUtils, System.Generics.Collections;
  27. {$ELSE FPC_DOTTEDUNITS}
  28. uses
  29. Classes, SysUtils, fasthtmlparser, contnrs, strutils, generics.collections;
  30. {$ENDIF FPC_DOTTEDUNITS}
  31. type
  32. TChmSiteMapItems = class; // forward
  33. TChmSiteMap = class;
  34. TChmSiteMapItem = class;
  35. { TChmSiteMapItem }
  36. TChmSiteMapItemAttrName = (siteattr_NONE,
  37. siteattr_KEYWORD, // alias for name in sitemap
  38. siteattr_NAME,
  39. siteattr_LOCAL,
  40. siteattr_URL,
  41. siteattr_TYPE,
  42. siteattr_SEEALSO,
  43. siteattr_IMAGENUMBER,
  44. siteattr_NEW,
  45. siteattr_COMMENT,
  46. siteattr_MERGE,
  47. siteattr_FRAMENAME,
  48. siteattr_WINDOWNAME,
  49. siteattr_WINDOW_STYLES,
  50. siteattr_EXWINDOW_STYLES,
  51. siteattr_FONT,
  52. siteattr_IMAGELIST,
  53. siteattr_IMAGETYPE,
  54. siteattr_BACKGROUND,
  55. siteattr_FOREGROUND
  56. );
  57. { TChmSiteMapSubItem }
  58. TChmSiteMapGenerationOptions = (Default,emitkeyword);
  59. TChmSiteMapSubItem = class(TPersistent)
  60. private
  61. FName,
  62. FType,
  63. FLocal,
  64. FUrl,
  65. FSeeAlso : String;
  66. FOwner : TChmSiteMapItem;
  67. public
  68. constructor Create(AOwner: TChmSiteMapItem);
  69. destructor Destroy; override;
  70. published
  71. property Name : String read FName write FName; //hhk
  72. property ItemType : String read FType write FType; //both
  73. property Local: String read FLocal write FLocal; //both
  74. property URL : String read FURL write FURL; //both
  75. property SeeAlso: String read FSeeAlso write FSeeAlso; //hhk
  76. end;
  77. // hhk items: Merge | ([Name] ([Name] [Type...] [Local [URL] | See Also])... [FrameName] [WindowName] [Comment])
  78. // hhc items: Merge | ([Name] ([Type...] [Local] [URL])... [FrameName] [WindowName] [Comment] [New] [ImageNumber])
  79. TChmSiteMapItem = class(TPersistent)
  80. private
  81. FChildren: TChmSiteMapItems;
  82. FComment: String;
  83. FImageNumber: Integer;
  84. FIncreaseImageIndex: Boolean;
  85. FOwner: TChmSiteMapItems;
  86. FName : String;
  87. FMerge : String;
  88. FFrameName : String;
  89. FWindowName : String;
  90. FSubItems : TObjectList;
  91. function getlocal: string;
  92. function getseealso:string;
  93. function getsubitem( index : integer): TChmSiteMapSubItem;
  94. function getsubitemcount: integer;
  95. procedure SetChildren(const AValue: TChmSiteMapItems);
  96. public
  97. constructor Create(AOwner: TChmSiteMapItems);
  98. destructor Destroy; override;
  99. procedure AddName(const Name:string);
  100. procedure AddLocal(const Local:string);
  101. procedure AddSeeAlso(const SeeAlso:string);
  102. procedure AddURL(const URL:string);
  103. procedure AddType(const AType:string);
  104. procedure Sort(Compare: TListSortCompare);
  105. published
  106. property Children: TChmSiteMapItems read FChildren write SetChildren;
  107. property Name: String read FName write FName;
  108. property ImageNumber: Integer read FImageNumber write FImageNumber default -1;
  109. property IncreaseImageIndex: Boolean read FIncreaseImageIndex write FIncreaseImageIndex;
  110. property Comment: String read FComment write FComment;
  111. property Owner: TChmSiteMapItems read FOwner;
  112. property Keyword : string read fname; // deprecated; // Use name, sitemaps don't store the difference.
  113. property Local : string read getlocal; // deprecated; // should work on ALL pairs
  114. property Text : string read fname write fname; // deprecated; // should work on ALL pairs
  115. property SeeAlso : string read getseealso; // deprecated; // should work on ALL pairs
  116. property FrameName: String read FFrameName write FFrameName;
  117. property WindowName: String read FWindowName write FWindowName;
  118. property Merge: String read FMerge write FMerge;
  119. property SubItem[ index :integer]:TChmSiteMapSubItem read getsubitem;
  120. property SubItemcount :integer read getsubitemcount;
  121. end;
  122. { TChmSiteMapItems }
  123. TChmSiteMapItems = class(TPersistent)
  124. private
  125. FInternalData: Dword;
  126. FList: TList;
  127. FOwner: TChmSiteMap;
  128. FParentItem: TChmSiteMapItem;
  129. function GetCount: Integer;
  130. function GetItem(AIndex: Integer): TChmSiteMapItem;
  131. function getparentname: String;
  132. procedure SetItem(AIndex: Integer; const AValue: TChmSiteMapItem);
  133. public
  134. constructor Create(AOwner: TChmSiteMap; AParentItem: TChmSiteMapItem);
  135. destructor Destroy; override;
  136. procedure Delete(AIndex: Integer);
  137. function Add(AItem: TChmSiteMapItem): Integer;
  138. function NewItem: TChmSiteMapItem;
  139. function Insert(AItem: TChmSiteMapItem; AIndex: Integer): Integer;
  140. procedure Clear;
  141. procedure Sort(Compare: TListSortCompare);
  142. property Item[AIndex: Integer]: TChmSiteMapItem read GetItem write SetItem;
  143. property Count: Integer read GetCount;
  144. property ParentItem: TChmSiteMapItem read FParentItem;
  145. property Owner: TChmSiteMap read FOwner;
  146. property InternalData: Dword read FInternalData write FInternalData;
  147. property ParentName : String read getparentname;
  148. end;
  149. { TChmSiteMapTree }
  150. TSiteMapType = (stTOC, stIndex);
  151. TSiteMapTag = (smtUnknown, smtNone, smtHTML, smtHEAD, smtBODY);
  152. TSiteMapTags = set of TSiteMapTag;
  153. TSiteMapBodyTag = (smbtUnknown, smbtNone, smbtUL, smbtLI, smbtOBJECT, smbtPARAM);
  154. TSiteMapBodyTags = set of TSiteMapBodyTag;
  155. TLIObjectParamType = (ptName, ptLocal, ptKeyword);
  156. TChmSiteMap = class
  157. private
  158. FAutoGenerated: Boolean;
  159. FBackgroundColor: LongInt;
  160. FCurrentItems: TChmSiteMapItems;
  161. FExWindowStyles: LongInt;
  162. FFont: String;
  163. FForegroundColor: LongInt;
  164. FFrameName: String;
  165. FImageList: String;
  166. FImageWidth: Integer;
  167. FSiteMapTags: TSiteMapTags;
  168. FSiteMapBodyTags: TSiteMapBodyTags;
  169. FHTMLParser: THTMLParser;
  170. FItems: TChmSiteMapItems;
  171. FSiteMapType: TSiteMapType;
  172. FUseFolderImages: Boolean;
  173. FWindowName: String;
  174. FLevel: Integer;
  175. FLevelForced: Boolean;
  176. FWindowStyles: LongInt;
  177. FLoadDict : TDictionary<String,TChmSiteMapItemAttrName>;
  178. fChmSiteMapGenerationOptions:TChmSiteMapGenerationOptions;
  179. procedure SetItems(const AValue: TChmSiteMapItems);
  180. procedure CheckLookup;
  181. protected
  182. procedure FoundTag (ACaseInsensitiveTag, AActualTag: Ansistring);
  183. procedure FoundText(AText: Ansistring);
  184. public
  185. constructor Create(AType: TSiteMapType);
  186. destructor Destroy; override;
  187. Procedure Sort(Compare: TListSortCompare);
  188. procedure LoadFromFile(AFileName: String);
  189. procedure LoadFromStream(AStream: TStream);
  190. procedure SaveToFile(AFileName:String);
  191. procedure SaveToStream(AStream: TStream);
  192. property Items: TChmSiteMapItems read FItems write SetItems;
  193. property SiteMapType: TSiteMapType read FSiteMapType;
  194. // SiteMap properties. most of these are invalid for the index
  195. property FrameName: String read FFrameName write FFrameName;
  196. property WindowName: String read FWindowName write FWindowName;
  197. property ImageList: String read FImageList write FImageList;
  198. property ImageWidth: Integer read FImageWidth write FImageWidth;
  199. property BackgroundColor: LongInt read FBackgroundColor write FBackgroundColor;
  200. property ForegroundColor: LongInt read FForegroundColor write FForegroundColor;
  201. property ExWindowStyles: LongInt read FExWindowStyles write FExWindowStyles;
  202. property WindowStyles: LongInt read FWindowStyles write FWindowStyles;
  203. property UseFolderImages: Boolean read FUseFolderImages write FUseFolderImages;
  204. property Font: String read FFont write FFont;
  205. property AutoGenerated: Boolean read FAutoGenerated write FAutoGenerated;
  206. property ChmSiteMapGenerationOptions : TChmSiteMapGenerationOptions read fChmSiteMapGenerationOptions write fChmSiteMapGenerationOptions;
  207. end;
  208. function indexitemcompare(Item1, Item2: Pointer): Integer;
  209. implementation
  210. {$IFDEF FPC_DOTTEDUNITS}
  211. uses Chm.HtmlUtil;
  212. {$ELSE FPC_DOTTEDUNITS}
  213. uses HTMLUtil;
  214. {$ENDIF FPC_DOTTEDUNITS}
  215. const sitemapkws : array[TChmSiteMapItemAttrName] of string = (
  216. '',
  217. 'KEYWORD',
  218. 'NAME',
  219. 'LOCAL',
  220. 'URL',
  221. 'TYPE',
  222. 'SEE ALSO',
  223. 'IMAGENUMBER',
  224. 'NEW',
  225. 'COMMENT',
  226. 'MERGE',
  227. 'FRAMENAME',
  228. 'WINDOWNAME',
  229. 'WINDOW STYLES',
  230. 'EXWINDOW STYLES',
  231. 'FONT',
  232. 'IMAGELIST',
  233. 'IMAGETYPE',
  234. 'BACKGROUND',
  235. 'FOREGROUND');
  236. function indexitemcompare(Item1, Item2: Pointer): Integer;
  237. begin
  238. Result := naturalComparetext(LowerCase(TChmSiteMapItem(item1).name), Lowercase(TChmSiteMapItem(item2).name));
  239. end;
  240. { TChmSiteMapSubItem }
  241. constructor TChmSiteMapSubItem.Create(AOwner: TChmSiteMapItem);
  242. begin
  243. FOwner:=AOwner;
  244. end;
  245. destructor TChmSiteMapSubItem.Destroy;
  246. begin
  247. inherited Destroy;
  248. end;
  249. { TChmSiteMapTree }
  250. procedure TChmSiteMap.SetItems(const AValue: TChmSiteMapItems);
  251. begin
  252. if FItems=AValue then exit;
  253. FItems:=AValue;
  254. end;
  255. procedure TChmSiteMap.CheckLookup;
  256. var en : TChmSiteMapItemAttrName;
  257. begin
  258. if assigned(FLoadDict) then
  259. exit;
  260. FLoadDict :=TDictionary<String,TChmSiteMapItemAttrName>.Create;
  261. for en:=succ(low(en)) to high(en) do
  262. FLoadDict.add(sitemapkws[en],en);
  263. end;
  264. procedure TChmSiteMap.FoundTag(ACaseInsensitiveTag, AActualTag: Ansistring);
  265. procedure NewSiteMapItem;
  266. begin
  267. FCurrentItems.Add(TChmSiteMapItem.Create(FCurrentItems));
  268. end;
  269. function ActiveItem: TChmSiteMapItem;
  270. begin
  271. if FCurrentItems.Count=0 then
  272. NewSiteMapItem;
  273. Result := FCurrentItems.Item[FCurrentItems.Count-1]
  274. end;
  275. procedure IncreaseULevel;
  276. begin
  277. if FCurrentItems = nil then FCurrentItems := Items
  278. else begin
  279. //WriteLn('NewLevel. Count = ', FCurrentItems.Count, ' Index = ',Items.Count-1);
  280. FCurrentItems := ActiveItem.Children;
  281. end;
  282. Inc(FLevel);
  283. end;
  284. procedure DecreaseULevel;
  285. begin
  286. if Assigned(FCurrentItems) and Assigned(FCurrentItems.ParentItem) then
  287. FCurrentItems := FCurrentItems.ParentItem.Owner
  288. else FCurrentItems := nil;
  289. Dec(FLevel);
  290. end;
  291. // hhk items: Merge | ([Name] ([Name] [Type...] [Local [URL] | See Also])... [FrameName] [WindowName] [Comment])
  292. // hhc items: Merge | ([Name] ([Type...] [Local] [URL])... [FrameName] [WindowName] [Comment] [New] [ImageNumber])
  293. var
  294. TagName,
  295. TagAttributeName,
  296. TagAttributeValue: String;
  297. isParam,IsMerged : string;
  298. TagAttrName : TChmSiteMapItemAttrName;
  299. begin
  300. TagName := GetTagName(ACaseInsensitiveTag);
  301. if TagName = 'UL' then begin
  302. IncreaseULevel;
  303. end
  304. else if TagName = '/UL' then begin
  305. DecreaseULevel;
  306. end
  307. else if (TagName = 'LI') and (FLevel = 0) then
  308. FLevelForced := True
  309. else if TagName = 'OBJECT' then begin
  310. Include(FSiteMapBodyTags, smbtOBJECT);
  311. if FLevelForced then
  312. IncreaseULevel;
  313. If FLevel > 0 then // if it is zero it is the site properties
  314. NewSiteMapItem;
  315. end
  316. else if TagName = '/OBJECT' then begin
  317. Exclude(FSiteMapBodyTags, smbtOBJECT);
  318. if FLevelForced then
  319. begin
  320. DecreaseULevel;
  321. FLevelForced := False;
  322. end;
  323. end
  324. else begin // we are the properties of the object tag
  325. if (smbtOBJECT in FSiteMapBodyTags) then
  326. begin
  327. if (FLevel > 0 ) then
  328. begin
  329. if LowerCase(GetTagName(AActualTag)) = 'param' then begin
  330. TagAttributeName := GetVal(AActualTag, 'name');
  331. TagAttributeValue := GetVal(AActualTag, 'value');
  332. // a hash reduces comparisons and casing, and generics make it easy.
  333. if not FLoadDict.trygetvalue(uppercase(TagAttributeName),TagAttrName) then
  334. TagAttrName:=siteattr_none;
  335. if TagAttrName <> siteattr_none then begin
  336. case TagAttrName of
  337. siteattr_KEYWORD,
  338. siteattr_NAME : Activeitem.AddName(TagAttributeValue);
  339. siteattr_LOCAL : ActiveItem.AddLocal(TagAttributeValue);
  340. siteattr_URL : ActiveItem.AddURL (TagAttributeValue);
  341. siteattr_TYPE : ActiveItem.AddType (TagAttributeValue);
  342. siteattr_SEEALSO : ActiveItem.AddSeeAlso(TagAttributeValue);
  343. siteattr_IMAGENUMBER : ActiveItem.ImageNumber := StrToInt(TagAttributeValue);
  344. siteattr_NEW : ActiveItem.IncreaseImageIndex := (LowerCase(TagAttributeValue) = 'yes');
  345. siteattr_COMMENT : ActiveItem.Comment := TagAttributeValue;
  346. siteattr_MERGE : ActiveItem.Merge:= TagAttributeValue;
  347. siteattr_FRAMENAME : ActiveItem.FrameName:=TagAttributeValue;
  348. siteattr_WINDOWNAME : ActiveItem.WindowName:=TagAttributeValue;
  349. end;
  350. end;
  351. end;
  352. end
  353. else
  354. begin // object and level is zero?
  355. if LowerCase(GetTagName(AActualTag)) = 'param' then begin
  356. begin
  357. TagAttributeName := uppercase(GetVal(AActualTag, 'name'));
  358. TagAttributeValue := GetVal(AActualTag, 'value');
  359. if not FLoadDict.trygetvalue(uppercase(TagAttributeName),TagAttrName) then
  360. TagAttrName:=siteattr_none;
  361. if TagAttrName <> siteattr_none then begin
  362. case TagAttrName of
  363. siteattr_FRAMENAME : FrameName:=TagAttributeValue;
  364. siteattr_WINDOWNAME : WindowName:=TagAttributeValue;
  365. siteattr_WINDOW_STYLES : WindowStyles:=StrToIntDef(TagAttributeValue,0);
  366. siteattr_EXWINDOW_STYLES : ExWindowStyles:=StrToIntDef(TagAttributeValue,0);
  367. siteattr_FONT : Font:=TagAttributeValue;
  368. siteattr_IMAGELIST : ImageList:=TagAttributeValue;
  369. siteattr_IMAGETYPE : UseFolderImages:=uppercase(TagAttributeValue)='FOLDER';
  370. siteattr_BACKGROUND : BackgroundColor:=strtointdef(trim(TagAttributeValue),longint(-1));
  371. siteattr_FOREGROUND : ForegroundColor:=strtointdef(trim(TagAttributeValue),0)
  372. end;
  373. end;
  374. // writeln('0:',flevel,' ' ,aactualtag,' ',tagname,' ' ,tagattributename, ' ' ,tagattributevalue);
  375. end;
  376. end;
  377. end;
  378. end;
  379. end;
  380. // end; {body}
  381. //end {html}
  382. end;
  383. procedure TChmSiteMap.FoundText(AText: ansistring);
  384. begin
  385. //WriteLn('TEXT:', AText);
  386. end;
  387. constructor TChmSiteMap.Create(AType: TSiteMapType);
  388. begin
  389. Inherited Create;
  390. FSiteMapType := AType;
  391. FSiteMapTags := [smtNone];
  392. FSiteMapBodyTags := [smbtNone];
  393. FHTMLParser:=nil;
  394. FItems := TChmSiteMapItems.Create(Self, nil); ;
  395. BackgroundColor:=-1;
  396. ForegroundColor:=-1;
  397. ExWindowStyles:=-1;
  398. end;
  399. destructor TChmSiteMap.Destroy;
  400. begin
  401. if Assigned(FHTMLParser) then FHTMLParser.Free;
  402. FItems.Free;
  403. FLoadDict.Free;
  404. Inherited Destroy;
  405. end;
  406. procedure TChmSiteMap.Sort(Compare: TListSortCompare);
  407. begin
  408. FItems.sort(compare);
  409. end;
  410. procedure TChmSiteMap.LoadFromFile(AFileName: String);
  411. var
  412. Buffer: String;
  413. TmpStream: TMemoryStream;
  414. begin
  415. CheckLookup;
  416. if Assigned(FHTMLParser) then FHTMLParser.Free;
  417. TmpStream := TMemoryStream.Create;
  418. try
  419. TmpStream.LoadFromFile(AFileName);
  420. SetLength(Buffer, TmpStream.Size);
  421. TmpStream.Position := 0;
  422. TmpStream.Read(Buffer[1], TmpStream.Size);
  423. finally
  424. TmpStream.Free;
  425. end;
  426. FHTMLParser := THTMLParser.Create(Buffer);
  427. try
  428. FHTMLParser.OnFoundTag := FoundTag;
  429. FHTMLParser.OnFoundText := FoundText;
  430. FHTMLParser.Exec;
  431. finally
  432. FreeAndNil(FHTMLParser);
  433. end;
  434. end;
  435. procedure TChmSiteMap.LoadFromStream(AStream: TStream);
  436. var
  437. Buffer: String;
  438. begin
  439. CheckLookup;
  440. if Assigned(FHTMLParser) then FHTMLParser.Free;
  441. SetLength(Buffer, AStream.Size-AStream.Position);
  442. if AStream.Read(Buffer[1], AStream.Size-AStream.Position) > 0 then begin;
  443. FHTMLParser := THTMLParser.Create(Buffer);
  444. FHTMLParser.OnFoundTag := FoundTag;
  445. FHTMLParser.OnFoundText := FoundText;
  446. FHTMLParser.Exec;
  447. FreeAndNil(FHTMLParser);
  448. end;
  449. end;
  450. procedure TChmSiteMap.SaveToFile(AFileName:String);
  451. var
  452. fs : TFileStream;
  453. begin
  454. fs:=TFileStream.Create(AFileName,fmcreate);
  455. try
  456. SaveToStream(fs);
  457. finally
  458. fs.free;
  459. end;
  460. end;
  461. // hhk items: Merge | ([Name] ([Name] [Type...] [Local [URL] | See Also])... [FrameName] [WindowName] [Comment])
  462. // hhc items: Merge | ([Name] ([Type...] [Local] [URL])... [FrameName] [WindowName] [Comment] [New] [ImageNumber])
  463. procedure TChmSiteMap.SaveToStream(AStream: TStream);
  464. var
  465. Indent: Integer;
  466. procedure WriteString(AString: String);
  467. var
  468. I: Integer;
  469. begin
  470. for I := 0 to Indent-1 do AStream.WriteByte(Byte(' '));
  471. AStream.Write(AString[1], Length(AString));
  472. AStream.WriteByte(10);
  473. end;
  474. procedure WriteStringNoIndent(AString: String);
  475. var
  476. I: Integer;
  477. begin
  478. AStream.Write(AString[1], Length(AString));
  479. end;
  480. procedure WriteParam(AName: String; AValue: String);
  481. begin
  482. WriteString('<param name="'+AName+'" value="'+AValue+'">');
  483. end;
  484. procedure WriteEntries(AItems: TChmSiteMapItems);
  485. var
  486. I,J : Integer;
  487. Item: TChmSiteMapItem;
  488. Sub : TChmSiteMapSubItem;
  489. lemitkeyword : boolean;
  490. begin
  491. lemitkeyword:=ChmSiteMapGenerationOptions=emitkeyword;
  492. for I := 0 to AItems.Count-1 do begin
  493. Item := AItems.Item[I];
  494. {$ifdef preferlower}
  495. WriteString('<li> <object type="text/sitemap">');
  496. {$else}
  497. WriteString('<LI> <OBJECT type="text/sitemap">');
  498. {$endif}
  499. Inc(Indent, 8);
  500. if Item.Name<>'' then
  501. begin
  502. if lemitkeyword then
  503. WriteParam('Keyword', item.Name)
  504. else
  505. WriteParam('Name', Item.Name);
  506. end;
  507. if item.FSubItems.count>0 then
  508. begin
  509. For j:=0 to item.FSubItems.count-1 do
  510. begin
  511. Sub:=TChmSiteMapSubItem(item.fsubitems[j]);
  512. if Sub.Name <> '' then WriteParam('Name', Sub.Name);
  513. if Sub.ItemType <> '' then WriteParam('Type', Sub.ItemType);
  514. if Sub.Local <> '' then WriteParam('Local', Sub.Local);
  515. if Sub.URL <> '' then WriteParam('URL', Sub.URL);
  516. if Sub.SeeAlso <> '' then WriteParam('See Also', Sub.SeeAlso);
  517. end;
  518. end;
  519. if Item.FrameName <> '' then WriteParam('FrameName', Item.FrameName);
  520. if Item.WindowName <> '' then WriteParam('WindowName', Item.WindowName);
  521. if Item.Comment <> '' then WriteParam('Comment', Item.Comment);
  522. if (SiteMapType = stTOC) and (Item.IncreaseImageIndex) then
  523. WriteParam('New', 'yes'); // is this a correct value?
  524. if (SiteMapType = stTOC) and (Item.ImageNumber <> -1) then
  525. WriteParam('ImageNumber', IntToStr(Item.ImageNumber));
  526. Dec(Indent, 3);
  527. {$ifdef preferlower}
  528. WriteString('</object>');
  529. {$else}
  530. WriteString('</OBJECT>');
  531. {$endif}
  532. Dec(Indent, 5);
  533. // Now Sub Entries
  534. if Item.Children.Count > 0 then begin
  535. {$ifdef preferlower}
  536. WriteString('<ul>');
  537. {$else}
  538. WriteString('<UL> ');
  539. {$endif}
  540. Inc(Indent, 8);
  541. WriteEntries(Item.Children);
  542. Dec(Indent, 8);
  543. {$ifdef preferlower}
  544. WriteString('</ul>');
  545. {$else}
  546. WriteString('</UL>'); //writestringnoident
  547. {$endif}
  548. end;
  549. end;
  550. end;
  551. begin
  552. Indent := 0;
  553. WriteString('<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">');
  554. WriteString('<HTML>');
  555. WriteString('<HEAD>');
  556. WriteString('<meta name="GENERATOR" content="Microsoft&reg; HTML Help Workshop 4.1">'); // Should we change this?
  557. WriteString('<!-- Sitemap 1.0 -->');
  558. WriteString('</HEAD><BODY>');
  559. // Site Properties
  560. WriteString('<OBJECT type="text/site properties">');
  561. Inc(Indent, 8);
  562. if SiteMapType = stTOC then begin
  563. if FrameName <> '' then WriteParam('FrameName', FrameName);
  564. if WindowName <> '' then WriteParam('WindowName', WindowName);
  565. if ImageList <> '' then WriteParam('ImageList', ImageList);
  566. if ImageWidth > 0 then WriteParam('Image Width', IntToStr(ImageWidth));
  567. if BackgroundColor <> 0 then WriteParam('Background', '0x'+hexStr(BackgroundColor, 8));
  568. if ForegroundColor <> 0 then WriteParam('Foreground', '0x'+hexStr(ForegroundColor, 8));
  569. if ExWindowStyles <> 0 then WriteParam('ExWindow Styles', '0x'+hexStr(ExWindowStyles, 8));
  570. if WindowStyles <> 0 then WriteParam('Window Styles', '0x'+hexStr(WindowStyles, 8));
  571. if UseFolderImages then WriteParam('ImageType', 'Folder');
  572. end;
  573. // both TOC and Index have font
  574. if Font <> '' then
  575. WriteParam('Font', Font);
  576. Dec(Indent, 8);
  577. WriteString('</OBJECT>');
  578. // And now the items
  579. if Items.Count > 0 then begin
  580. WriteString('<UL>');
  581. Inc(Indent, 8);
  582. // WriteEntries
  583. WriteEntries(Items);
  584. Dec(Indent, 8);
  585. WriteString('</UL>');
  586. end;
  587. WriteString('</BODY></HTML>');
  588. AStream.Size := AStream.Position;
  589. end;
  590. { TChmSiteMapItem }
  591. procedure TChmSiteMapItem.SetChildren(const AValue: TChmSiteMapItems);
  592. begin
  593. if FChildren = AValue then exit;
  594. FChildren := AValue;
  595. end;
  596. function TChmSiteMapItem.getlocal: string;
  597. begin
  598. result:='';
  599. if FSubItems.count>0 then
  600. result:=TChmSiteMapSubItem(FSubItems[0]).local;
  601. end;
  602. function TChmSiteMapItem.getseealso: string;
  603. begin
  604. result:='';
  605. if FSubItems.count>0 then
  606. result:=TChmSiteMapSubItem(FSubItems[FSubItems.count-1]).SeeAlso;
  607. end;
  608. function TChmSiteMapItem.getsubitem( index : integer): TChmSiteMapSubItem;
  609. begin
  610. result:=nil;
  611. if index<FSubItems.count then
  612. result:=TChmSiteMapSubItem(FSubItems[index]);
  613. end;
  614. function TChmSiteMapItem.getsubitemcount: integer;
  615. begin
  616. result:=FSubItems.count;
  617. end;
  618. constructor TChmSiteMapItem.Create(AOwner: TChmSiteMapItems);
  619. begin
  620. Inherited Create;
  621. FOwner := AOwner;
  622. FChildren := TChmSiteMapItems.Create(Owner.Owner, Self);
  623. FSubItems := TObjectList.Create(true);
  624. imagenumber:=-1;
  625. end;
  626. destructor TChmSiteMapItem.Destroy;
  627. begin
  628. fsubitems.Free;
  629. FChildren.Free;
  630. Inherited Destroy;
  631. end;
  632. procedure TChmSiteMapItem.AddName(const Name: string);
  633. var sub :TChmSiteMapSubItem;
  634. begin
  635. if fname='' then
  636. fname:=name
  637. else
  638. begin
  639. sub :=TChmSiteMapSubItem.create(self);
  640. FSubItems.add(sub);
  641. sub.Name:=Name;
  642. end;
  643. end;
  644. procedure TChmSiteMapItem.AddLocal(const Local: string);
  645. var sub :TChmSiteMapSubItem;
  646. addnew : boolean;
  647. begin
  648. if fsubitems.count>0 then
  649. begin
  650. sub:=TChmSiteMapSubItem(fsubitems[FSubItems.count-1]);
  651. if sub.FLocal<>'' then
  652. begin
  653. sub.flocal:=local;
  654. exit;
  655. end;
  656. end;
  657. sub :=TChmSiteMapSubItem.create(self);
  658. FSubItems.add(sub);
  659. // sub.name:=name;
  660. sub.Local:=Local;
  661. end;
  662. procedure TChmSiteMapItem.AddSeeAlso(const SeeAlso: string);
  663. // see also is mutually exclusive with "local url", so addition procedure is same as "local"
  664. var sub :TChmSiteMapSubItem;
  665. begin
  666. if fsubitems.count>0 then
  667. begin
  668. sub:=TChmSiteMapSubItem(fsubitems[FSubItems.count-1]);
  669. if sub.FSeeAlso<>'' then
  670. begin
  671. sub.FSeeAlso:=SeeAlso;
  672. exit;
  673. end;
  674. end;
  675. sub :=TChmSiteMapSubItem.create(self);
  676. FSubItems.add(sub);
  677. sub.FSeeAlso:=SeeAlso;
  678. end;
  679. procedure TChmSiteMapItem.AddURL(const URL: string);
  680. var sub :TChmSiteMapSubItem;
  681. begin
  682. if fsubitems.count>0 then
  683. begin
  684. sub:=TChmSiteMapSubItem(fsubitems[FSubItems.count-1]);
  685. if sub.FURL<>'' then
  686. begin
  687. sub.fURL:=URL;
  688. exit;
  689. end;
  690. end
  691. { else not possible according to chmspec. An URL must always follow a "local" item}
  692. end;
  693. procedure TChmSiteMapItem.AddType(const AType: string);
  694. // in Tocs, Type can be the first is the same as local
  695. var sub :TChmSiteMapSubItem;
  696. begin
  697. if fsubitems.count>0 then
  698. begin
  699. sub:=TChmSiteMapSubItem(fsubitems[FSubItems.count-1]);
  700. if sub.ItemType<>'' then
  701. begin
  702. sub.ItemType:=AType;
  703. exit;
  704. end;
  705. end;
  706. sub :=TChmSiteMapSubItem.create(self);
  707. FSubItems.add(sub);
  708. sub.ItemType:=AType;
  709. end;
  710. procedure TChmSiteMapItem.Sort(Compare: TListSortCompare);
  711. begin
  712. FChildren.sort(compare);
  713. end;
  714. { TChmSiteMapItems }
  715. function TChmSiteMapItems.GetItem(AIndex: Integer): TChmSiteMapItem;
  716. begin
  717. Result := TChmSiteMapItem(FList.Items[AIndex]);
  718. end;
  719. function TChmSiteMapItems.getparentname: String;
  720. begin
  721. result:='Not assigned';
  722. if assigned(fparentitem) then
  723. begin
  724. result:=FParentItem.name;
  725. end;
  726. end;
  727. function TChmSiteMapItems.GetCount: Integer;
  728. begin
  729. Result := FList.Count;
  730. end;
  731. procedure TChmSiteMapItems.SetItem(AIndex: Integer; const AValue: TChmSiteMapItem);
  732. begin
  733. FList.Items[AIndex] := AValue;
  734. end;
  735. constructor TChmSiteMapItems.Create(AOwner: TChmSiteMap; AParentItem: TChmSiteMapItem);
  736. begin
  737. FList := TList.Create;
  738. FParentItem := AParentItem;
  739. FOwner := AOwner;
  740. FInternalData := maxLongint;
  741. end;
  742. destructor TChmSiteMapItems.Destroy;
  743. begin
  744. Clear;
  745. FList.Free;
  746. inherited Destroy;
  747. end;
  748. procedure TChmSiteMapItems.Delete(AIndex: Integer);
  749. begin
  750. Item[AIndex].Free;
  751. FList.Delete(AIndex);
  752. end;
  753. function TChmSiteMapItems.Add(AItem: TChmSiteMapItem): Integer;
  754. begin
  755. Result := FList.Add(AItem);
  756. end;
  757. function TChmSiteMapItems.NewItem: TChmSiteMapItem;
  758. begin
  759. Result := TChmSiteMapItem.Create(Self);
  760. Add(Result);
  761. end;
  762. function TChmSiteMapItems.Insert(AItem: TChmSiteMapItem; AIndex: Integer): Integer;
  763. begin
  764. Result := AIndex;
  765. FList.Insert(AIndex, AItem);
  766. end;
  767. procedure TChmSiteMapItems.Clear;
  768. var
  769. I: LongInt;
  770. begin
  771. for I := Count-1 downto 0 do Delete(I);
  772. end;
  773. procedure TChmSiteMapItems.Sort(Compare: TListSortCompare);
  774. var I :Integer;
  775. begin
  776. FList.Sort(Compare);
  777. for i:=0 to flist.Count-1 do
  778. TChmSiteMapItem(flist[i]).sort(Compare)
  779. end;
  780. end.