source: tags/1.0.1/UAcronym.pas

Last change on this file was 34, checked in by chronos, 8 years ago
  • Fixed: Error during removing acronyms in case that multiple acronyms with same name exists.
File size: 37.2 KB
Line 
1unit UAcronym;
2
3{$mode delphi}{$H+}
4
5interface
6
7uses
8 Classes, SysUtils, Contnrs, XMLConf, XMLRead, XMLWrite, DOM, UXMLUtils,
9 SpecializedList, fphttpclient, Dialogs, odbcconn, sqldb;
10
11type
12 TAcronymCategories = class;
13 TAcronymMeanings = class;
14 TAcronymDb = class;
15 TImportSources = class;
16 TImportFormats = class;
17
18 TAcronymSource = class
19 Name: string;
20 URL: string;
21 end;
22
23 TAcronymSources = class(TObjectList)
24
25 end;
26
27 { TAcronym }
28
29 TAcronym = class
30 Db: TAcronymDb;
31 Name: string;
32 Meanings: TAcronymMeanings;
33 procedure SaveToNode(Node: TDOMNode);
34 procedure LoadFromNode(Node: TDOMNode);
35 constructor Create;
36 destructor Destroy; override;
37 end;
38
39 { TAcronyms }
40
41 TAcronyms = class(TObjectList)
42 Db: TAcronymDb;
43 procedure SaveToNode(Node: TDOMNode);
44 procedure LoadFromNode(Node: TDOMNode);
45 function SearchByName(Name: string): TAcronym;
46 function AddAcronym(Name: string): TAcronym;
47 end;
48
49 { TAcronymMeaning }
50
51 TAcronymMeaning = class
52 Id: Integer;
53 Name: string;
54 Description: string;
55 Language: string;
56 Acronym: TAcronym;
57 Categories: TAcronymCategories;
58 Source: TAcronymSource;
59 procedure SaveToNode(Node: TDOMNode);
60 procedure LoadFromNode(Node: TDOMNode);
61 constructor Create;
62 destructor Destroy; override;
63 end;
64
65 { TAcronymMeanings }
66
67 TAcronymMeanings = class(TObjectList)
68 public
69 Acronym: TAcronym;
70 procedure UpdateIds;
71 procedure SaveToNode(Node: TDOMNode);
72 procedure LoadFromNode(Node: TDOMNode);
73 function SearchByName(Name: string): TAcronymMeaning;
74 function AddMeaning(Name: string): TAcronymMeaning;
75 end;
76
77 { TAcronymCategory }
78
79 TAcronymCategory = class
80 Id: Integer;
81 Name: string;
82 AcronymMeanings: TAcronymMeanings;
83 procedure SaveToNode(Node: TDOMNode);
84 procedure LoadFromNode(Node: TDOMNode);
85 constructor Create;
86 destructor Destroy; override;
87 end;
88
89 { TAcronymCategories }
90
91 TAcronymCategories = class(TObjectList)
92 Db: TAcronymDb;
93 procedure UpdateIds;
94 procedure SaveToNode(Node: TDOMNode);
95 procedure LoadFromNode(Node: TDOMNode);
96 procedure SaveRefToNode(Node: TDOMNode);
97 procedure LoadRefFromNode(Node: TDOMNode);
98 function SearchByName(Name: string): TAcronymCategory;
99 function SearchById(Id: Integer): TAcronymCategory;
100 function AddContext(Name: string): TAcronymCategory;
101 procedure AssignToStrings(Strings: TStrings);
102 procedure AssignFromStrings(Strings: TStrings);
103 function GetString: string;
104 end;
105
106 { TAcronymEntry }
107
108 TAcronymEntry = class
109 Name: string;
110 Meaning: string;
111 Description: string;
112 Categories: TStringList;
113 constructor Create;
114 destructor Destroy; override;
115 end;
116
117 TImportPatternFlag = (ipfNone, ipfNewItem, ipfSkip);
118 TImportVariable = (ivNone, ivAcronym, ivMeaning, ivDescription);
119
120 { TImportPattern }
121
122 TImportPattern = class
123 StartString: string;
124 EndString: string;
125 Variable: TImportVariable;
126 Flag: TImportPatternFlag;
127 Repetition: Boolean;
128 procedure Assign(Source: TImportPattern);
129 procedure SaveToNode(Node: TDOMNode);
130 procedure LoadFromNode(Node: TDOMNode);
131 end;
132
133 { TImportPatterns }
134
135 TImportPatterns = class(TObjectList)
136 procedure SaveToNode(Node: TDOMNode);
137 procedure LoadFromNode(Node: TDOMNode);
138 end;
139
140 TImportFormatKind = (ifkParse, ifkMSAccess);
141
142 { TImportFormat }
143
144 TImportFormat = class
145 Id: Integer;
146 Name: string;
147 Kind: TImportFormatKind;
148 Block: TImportPattern;
149 ItemPatterns: TImportPatterns;
150 Formats: TImportFormats;
151 procedure Assign(Source: TImportFormat);
152 procedure SaveToNode(Node: TDOMNode);
153 procedure LoadFromNode(Node: TDOMNode);
154 constructor Create;
155 destructor Destroy; override;
156 end;
157
158 { TImportFormats }
159
160 TImportFormats = class(TObjectList)
161 procedure UpdateIds;
162 procedure SaveToNode(Node: TDOMNode);
163 procedure LoadFromNode(Node: TDOMNode);
164 function SearchByName(Name: string): TImportFormat;
165 function SearchById(Id: Integer): TImportFormat;
166 end;
167
168 { TImportSource }
169
170 TImportSource = class
171 private
172 procedure DoPassword(Sender: TObject; var RepeatRequest : Boolean);
173 public
174 Enabled: Boolean;
175 Name: string;
176 URL: string;
177 Format: TImportFormat;
178 LastTime: TDateTime;
179 Sources: TImportSources;
180 ItemCount: Integer;
181 Categories: TAcronymCategories;
182 function DownloadHTTP(URL: string; Stream: TStream): Boolean;
183 procedure Process;
184 procedure ProcessTextParse;
185 procedure ProcessMSAccess;
186 procedure Assign(Source: TImportSource);
187 procedure SaveToNode(Node: TDOMNode);
188 procedure LoadFromNode(Node: TDOMNode);
189 constructor Create;
190 destructor Destroy; override;
191 end;
192
193 { TImportSources }
194
195 TImportSources = class(TObjectList)
196 AcronymDb: TAcronymDb;
197 function SearchByName(Name: string): TImportSource;
198 procedure SaveToNode(Node: TDOMNode);
199 procedure LoadFromNode(Node: TDOMNode);
200 end;
201
202 { TAcronymDb }
203
204 TAcronymDb = class
205 FileName: string;
206 Sources: TAcronymSources;
207 Acronyms: TAcronyms;
208 Categories: TAcronymCategories;
209 ImportSources: TImportSources;
210 ImportFormats: TImportFormats;
211 Modified: Boolean;
212 constructor Create;
213 destructor Destroy; override;
214 procedure LoadFromFile(FileName: string);
215 procedure SaveToFile(FileName: string);
216 procedure LoadFromFileCSV(FileName: string);
217 procedure SaveToFileCSV(FileName: string);
218 procedure FilterList(AName: string; Items: TAcronymMeanings);
219 function AddAcronym(AcronymName, MeaningName: string): TAcronymMeaning;
220 procedure RemoveMeaning(Meaning: TAcronymMeaning);
221 procedure RemoveAcronym(AcronymName, MeaningName: string);
222 procedure AssignToList(List: TListObject);
223 end;
224
225function AcronymComparer(Item1, Item2: Pointer): Integer;
226
227const
228 ImportVariableString: array [TImportVariable] of string = ('None', 'Acronym',
229 'Meaning', 'Description');
230 ImportPatternFlagString: array [TImportPatternFlag] of string = ('None', 'New item',
231 'Skip');
232
233
234implementation
235
236resourcestring
237 SWrongFileFormat = 'Wrong file format';
238
239
240function AcronymComparer(Item1, Item2: Pointer): Integer;
241begin
242 Result := CompareStr(TAcronym(Item1).Name, TAcronym(Item2).Name);
243end;
244
245{ TImportSourceMSAccess }
246
247procedure TImportSource.ProcessMSAccess;
248var
249 ODBCConnection1: TODBCConnection;
250 SQLTransaction1: TSQLTransaction;
251 SQLQuery1: TSQLQuery;
252 NewAcronym: TAcronymEntry;
253begin
254 ItemCount := 0;
255 ODBCConnection1 := TODBCCOnnection.Create(nil);
256 SQLQuery1 := TSQLQuery.Create(nil);
257 SQLTransaction1 := TSQLTransaction.Create(nil);
258 try
259 ODBCConnection1.Driver := 'Microsoft Access Driver (*.mdb, *.accdb)';
260 ODBCConnection1.Params.Add('DBQ=' + URL);
261 ODBCConnection1.Params.Add('Locale Identifier=1031');
262 ODBCConnection1.Params.Add('ExtendedAnsiSQL=1');
263 ODBCConnection1.Params.Add('CHARSET=ansi');
264 ODBCConnection1.Connected := True;
265 ODBCConnection1.KeepConnection := True;
266
267 SQLTransaction1.DataBase := ODBCConnection1;
268 SQLTransaction1.Action := caCommit;
269 SQLTransaction1.Active := True;
270
271 SQLQuery1.DataBase := ODBCConnection1;
272 SQLQuery1.UsePrimaryKeyAsKey := False;
273 SQLQuery1.SQL.Text := 'SELECT Acronym,Meaning FROM data1';
274 SQLQuery1.Open;
275
276 NewAcronym := TAcronymEntry.Create;
277 while not SQLQuery1.EOF do begin
278 NewAcronym.Name := SQLQuery1.FieldByName('Acronym').AsString;
279 NewAcronym.Meaning := SQLQuery1.FieldByName('Meaning').AsString;
280 Sources.AcronymDb.AddAcronym(NewAcronym.Name, NewAcronym.Meaning);
281 SQLQuery1.Next;
282 Inc(ItemCount);
283 end;
284 NewAcronym.Free;
285 finally
286 SQLQuery1.Free;
287 SQLTransaction1.Free;
288 ODBCConnection1.Free;
289 end;
290end;
291
292{ TImportPatterns }
293
294procedure TImportPatterns.SaveToNode(Node: TDOMNode);
295var
296 I: Integer;
297 NewNode2: TDOMNode;
298begin
299 for I := 0 to Count - 1 do
300 with TImportPattern(Items[I]) do begin
301 NewNode2 := Node.OwnerDocument.CreateElement('Pattern');
302 Node.AppendChild(NewNode2);
303 SaveToNode(NewNode2);
304 end;
305end;
306
307procedure TImportPatterns.LoadFromNode(Node: TDOMNode);
308var
309 Node2: TDOMNode;
310 NewItem: TImportPattern;
311begin
312 Count := 0;
313 Node2 := Node.FirstChild;
314 while Assigned(Node2) and (Node2.NodeName = 'Pattern') do begin
315 NewItem := TImportPattern.Create;
316 NewItem.LoadFromNode(Node2);
317 Add(NewItem);
318 Node2 := Node2.NextSibling;
319 end;
320end;
321
322{ TImportPattern }
323
324procedure TImportPattern.Assign(Source: TImportPattern);
325begin
326 StartString := Source.StartString;
327 EndString := Source.EndString;
328 Variable := Source.Variable;
329 Flag := Source.Flag;
330 Repetition := Source.Repetition;
331end;
332
333procedure TImportPattern.SaveToNode(Node: TDOMNode);
334begin
335 WriteString(Node, 'StartString', StartString);
336 WriteString(Node, 'EndString', EndString);
337 WriteInteger(Node, 'Variable', Integer(Variable));
338 WriteInteger(Node, 'Flag', Integer(Flag));
339 WriteBoolean(Node, 'Repetition', Repetition);
340end;
341
342procedure TImportPattern.LoadFromNode(Node: TDOMNode);
343begin
344 StartString := ReadString(Node, 'StartString', '');
345 EndString := ReadString(Node, 'EndString', '');
346 Variable := TImportVariable(ReadInteger(Node, 'Variable', 0));
347 Flag := TImportPatternFlag(ReadInteger(Node, 'Flag', 0));
348 Repetition := ReadBoolean(Node, 'Repetition', False);
349end;
350
351procedure TImportSource.DoPassword(Sender: TObject; var RepeatRequest: Boolean);
352begin
353 if TFPHttpClient(Sender).Password = '' then begin
354 TFPHttpClient(Sender).UserName := 'test';
355 TFPHttpClient(Sender).Password := 'test';
356 RepeatRequest := True;
357 end else RepeatRequest := False;
358end;
359
360function TImportSource.DownloadHTTP(URL: string; Stream: TStream): Boolean;
361var
362 HTTPClient: TFPHTTPClient;
363 FormData: TStringList;
364begin
365 HTTPClient := TFPHttpClient.Create(nil);
366 HTTPClient.OnPassword := DoPassword;
367 FormData := TStringList.Create;
368(*
369FormData.action=clientlogin
370 &loginreturnurl=http://example.com/&
371 logintoken=29590a3037d325be70b93fb8258ed29257448cfb%2B%5C&
372 username=Bob&
373 password=secret&
374 rememberMe=1
375 HTTPClient.FormPost(URL, FormData, Stream);
376 *)
377 HTTPClient.Get(URL, Stream);
378 FormData.Free;
379 HTTPClient.Free;
380 Result := True;
381end;
382
383procedure TImportSource.Process;
384begin
385 case Format.Kind of
386 ifkParse: ProcessTextParse;
387 ifkMSAccess: ProcessMSAccess;
388 else raise Exception.Create('Unsupported import format');
389 end;
390end;
391
392function StripHTML(S: string): string;
393var
394 TagBegin, TagEnd, TagLength: Integer;
395begin
396 TagBegin := Pos( '<', S); // search position of first <
397
398 while (TagBegin > 0) do begin // while there is a < in S
399 TagEnd := Pos('>', S); // find the matching >
400 if TagEnd = 0 then TagLength := Length(S) - TagBegin
401 else TagLength := TagEnd - TagBegin + 1;
402 if TagLength > 0 then
403 Delete(S, TagBegin, TagLength) // delete the tag
404 else Delete(S, 1, TagEnd); // delete the tag
405 TagBegin := Pos( '<', S); // search for next <
406 end;
407
408 Result := S; // give the result
409end;
410
411{ TImportFormat }
412
413procedure TImportFormat.Assign(Source: TImportFormat);
414var
415 I: Integer;
416begin
417 Kind := Source.Kind;
418 Name := Source.Name;
419 Block.StartString := Source.Block.StartString;
420 Block.EndString := Source.Block.EndString;
421 while ItemPatterns.Count < Source.ItemPatterns.Count do
422 ItemPatterns.Add(TImportPattern.Create);
423 if ItemPatterns.Count > Source.ItemPatterns.Count then
424 ItemPatterns.Count := Source.ItemPatterns.Count;
425 for I := 0 to ItemPatterns.Count - 1 do begin
426 TImportPattern(ItemPatterns[I]).Assign(TImportPattern(Source.ItemPatterns[I]));
427 end;
428end;
429
430procedure TImportFormat.SaveToNode(Node: TDOMNode);
431var
432 NewNode: TDOMNode;
433begin
434 WriteInteger(Node, 'Id', Id);
435 WriteString(Node, 'Name', Name);
436 WriteInteger(Node, 'Kind', Integer(Kind));
437 WriteString(Node, 'BlockStartString', Block.StartString);
438 WriteString(Node, 'BlockEndString', Block.EndString);
439
440 NewNode := Node.OwnerDocument.CreateElement('Patterns');
441 Node.AppendChild(NewNode);
442 ItemPatterns.SaveToNode(NewNode);
443end;
444
445procedure TImportFormat.LoadFromNode(Node: TDOMNode);
446var
447 NewNode: TDOMNode;
448begin
449 Id := ReadInteger(Node, 'Id', 0);
450 Name := ReadString(Node, 'Name', '');
451 Kind := TImportFormatKind(ReadInteger(Node, 'Kind', 0));
452 Block.StartString := ReadString(Node, 'BlockStartString', '');
453 Block.EndString := ReadString(Node, 'BlockEndString', '');
454
455 NewNode := Node.FindNode('Patterns');
456 if Assigned(NewNode) then
457 ItemPatterns.LoadFromNode(NewNode);
458end;
459
460constructor TImportFormat.Create;
461begin
462 Block := TImportPattern.Create;
463 ItemPatterns := TImportPatterns.Create;
464end;
465
466destructor TImportFormat.Destroy;
467begin
468 Block.Free;
469 ItemPatterns.Free;
470 inherited Destroy;
471end;
472
473{ TImportSources }
474
475function TImportSources.SearchByName(Name: string): TImportSource;
476var
477 I: Integer;
478begin
479 I := 0;
480 while (I < Count) and (TImportSource(Items[I]).Name <> Name) do Inc(I);
481 if I < Count then Result := TImportSource(Items[I])
482 else Result := nil;
483end;
484
485procedure TImportSources.SaveToNode(Node: TDOMNode);
486var
487 I: Integer;
488 NewNode2: TDOMNode;
489begin
490 for I := 0 to Count - 1 do
491 with TImportSource(Items[I]) do begin
492 NewNode2 := Node.OwnerDocument.CreateElement('ImportSource');
493 Node.AppendChild(NewNode2);
494 SaveToNode(NewNode2);
495 end;
496end;
497
498procedure TImportSources.LoadFromNode(Node: TDOMNode);
499var
500 Node2: TDOMNode;
501 NewItem: TImportSource;
502begin
503 Count := 0;
504 Node2 := Node.FirstChild;
505 while Assigned(Node2) and (Node2.NodeName = 'ImportSource') do begin
506 NewItem := TImportSource.Create;
507 NewItem.Sources := Self;
508 NewItem.LoadFromNode(Node2);
509 Add(NewItem);
510 Node2 := Node2.NextSibling;
511 end;
512end;
513
514{ TImportFormats }
515
516function TImportFormats.SearchByName(Name: string): TImportFormat;
517var
518 I: Integer;
519begin
520 I := 0;
521 while (I < Count) and (TImportFormat(Items[I]).Name <> Name) do Inc(I);
522 if I < Count then Result := TImportFormat(Items[I])
523 else Result := nil;
524end;
525
526procedure TImportFormats.UpdateIds;
527var
528 LastId: Integer;
529 I: Integer;
530begin
531 // Get highest used ID
532 LastId := 0;
533 for I := 0 to Count - 1 do begin
534 if TImportFormat(Items[I]).Id > LastId then LastId := TImportFormat(Items[I]).Id;
535 end;
536 // Add ID to new items without ID
537 for I := 0 to Count - 1 do begin
538 if TImportFormat(Items[I]).Id = 0 then begin
539 Inc(LastId);
540 TImportFormat(Items[I]).Id := LastId;
541 end;
542 end;
543end;
544
545procedure TImportFormats.SaveToNode(Node: TDOMNode);
546var
547 I: Integer;
548 NewNode2: TDOMNode;
549begin
550 UpdateIds;
551 for I := 0 to Count - 1 do
552 with TImportFormat(Items[I]) do begin
553 NewNode2 := Node.OwnerDocument.CreateElement('ImportFormat');
554 Node.AppendChild(NewNode2);
555 SaveToNode(NewNode2);
556 end;
557end;
558
559procedure TImportFormats.LoadFromNode(Node: TDOMNode);
560var
561 Node2: TDOMNode;
562 NewItem: TImportFormat;
563begin
564 Count := 0;
565 Node2 := Node.FirstChild;
566 while Assigned(Node2) and (Node2.NodeName = 'ImportFormat') do begin
567 NewItem := TImportFormat.Create;
568 NewItem.LoadFromNode(Node2);
569 Add(NewItem);
570 Node2 := Node2.NextSibling;
571 end;
572 UpdateIds;
573end;
574
575function TImportFormats.SearchById(Id: Integer): TImportFormat;
576var
577 I: Integer;
578begin
579 I := 0;
580 while (I < Count) and (TImportFormat(Items[I]).Id <> Id) do Inc(I);
581 if I < Count then Result := TImportFormat(Items[I])
582 else Result := nil;
583end;
584
585{ TImportSource }
586
587procedure TImportSource.ProcessTextParse;
588var
589 Stream: TMemoryStream;
590 S: string;
591 SS: string;
592 NewAcronym: TAcronymEntry;
593 P: Integer;
594 P1, P2: Integer;
595 Q: Integer;
596 I: Integer;
597 T: string;
598 LastLength: Integer;
599 AddedAcronym: TAcronymMeaning;
600begin
601 ItemCount := 0;
602 Stream := TMemoryStream.Create;
603 NewAcronym := TAcronymEntry.Create;
604 try
605 if DownloadHTTP(URL, Stream) then begin
606 Stream.Position := 0;
607 SetLength(S, Stream.Size);
608 Stream.Read(S[1], Length(S));
609
610 // Find main block
611 if Format.Block.StartString <> '' then begin
612 P := Pos(Format.Block.StartString, S);
613 if P > 0 then
614 Delete(S, 1, P + Length(Format.Block.StartString) - 1);
615 end;
616 if Format.Block.EndString <> '' then begin
617 P := Pos(Format.Block.EndString, S);
618 if P > 0 then
619 Delete(S, P, Length(S));
620 end;
621
622 // Remove unneeded items
623 repeat
624 LastLength := Length(S);
625 for I := 0 to Format.ItemPatterns.Count - 1 do
626 with TImportPattern(Format.ItemPatterns[I]) do
627 if Flag = ipfSkip then begin
628 P := Pos(StartString, S);
629 if P > 0 then begin
630 SS := Copy(S, P + Length(StartString), Length(S));
631 Q := Pos(EndString, SS);
632 if Q > 0 then begin
633 Delete(S, P, Q + Length(EndString) + Length(StartString) - 1);
634 end;
635 end;
636 end;
637 until Length(S) = LastLength;
638
639 // Find items
640 repeat
641 LastLength := Length(S);
642 I := 0;
643 while I < Format.ItemPatterns.Count do
644 with TImportPattern(Format.ItemPatterns[I]) do begin
645 if Flag <> ipfSkip then begin
646 if Length(StartString) > 0 then begin
647 P := Pos(StartString, S);
648 if P > 0 then Delete(S, 1, P + Length(StartString) - 1);
649 end;
650
651 if ((Length(StartString) > 0) and (P > 0)) or (Length(StartString) = 0) then begin
652 P := Pos(EndString, S);
653 T := StripHTML(Copy(S, 1, P - 1));
654 T := StringReplace(T, '&quot;', '"', [rfReplaceAll]);
655 T := StringReplace(T, '&trade;', 'TM', [rfReplaceAll]);
656 T := StringReplace(T, '&amp;', '&', [rfReplaceAll]);
657 T := StringReplace(T, '&#160;', ' ', [rfReplaceAll]); // No break space
658 T := Trim(T);
659 case Variable of
660 ivAcronym: NewAcronym.Name := T;
661 ivMeaning: NewAcronym.Meaning := T;
662 ivDescription: NewAcronym.Description := T;
663 end;
664 Delete(S, 1, P + Length(EndString) - 1);
665
666 if (Flag = ipfNewItem) and (Trim(NewAcronym.Name) <> '') and
667 (Trim(NewAcronym.Meaning) <> '') then begin
668 AddedAcronym := Sources.AcronymDb.AddAcronym(NewAcronym.Name, NewAcronym.Meaning);
669 AddedAcronym.Description := NewAcronym.Description;
670 AddedAcronym.Categories.Assign(Categories, laOr);
671 Inc(ItemCount);
672 end;
673
674 if Repetition then begin
675 if Length(StartString) > 0 then begin
676 P1 := Pos(StartString, S);
677 if P1 > 0 then begin
678 P2 := Pos(TImportPattern(Format.ItemPatterns[(I + 1) mod Format.ItemPatterns.Count]).StartString, S);
679 if (P2 > 0) and (P1 < P2) then Continue;
680 end;
681 end;
682 end;
683 end;
684 end;
685 Inc(I);
686 end;
687 until Length(S) = LastLength;
688 end;
689 finally
690 NewAcronym.Free;
691 Stream.Free;
692 end;
693end;
694
695procedure TImportSource.Assign(Source: TImportSource);
696begin
697 Enabled := Source.Enabled;
698 Name := Source.Name;
699 URL := Source.URL;
700 Format := Source.Format;
701 LastTime := Source.LastTime;
702 ItemCount := Source.ItemCount;
703 Categories.Assign(Source.Categories);
704end;
705
706procedure TImportSource.SaveToNode(Node: TDOMNode);
707var
708 NewNode: TDOMNode;
709begin
710 WriteString(Node, 'Name', Name);
711 WriteString(Node, 'URL', URL);
712 if Assigned(Format) then WriteInteger(Node, 'ImportFormat', Format.Id)
713 else WriteInteger(Node, 'ImportFormat', -1);
714 WriteBoolean(Node, 'Enabled', Enabled);
715 WriteInteger(Node, 'ItemCount', ItemCount);
716
717 NewNode := Node.OwnerDocument.CreateElement('Categories');
718 Node.AppendChild(NewNode);
719 Categories.SaveRefToNode(NewNode);
720end;
721
722procedure TImportSource.LoadFromNode(Node: TDOMNode);
723var
724 Node2: TDOMNode;
725begin
726 Name := ReadString(Node, 'Name', '');
727 URL := ReadString(Node, 'URL', '');
728 Format := Sources.AcronymDb.ImportFormats.SearchById(ReadInteger(Node, 'ImportFormat', -1));
729 Enabled := ReadBoolean(Node, 'Enabled', True);
730 ItemCount := ReadInteger(Node, 'ItemCount', 0);
731
732 Categories.Db := Sources.AcronymDb;
733 Node2 := Node.FindNode('Categories');
734 if Assigned(Node2) then
735 Categories.LoadRefFromNode(Node2);
736end;
737
738constructor TImportSource.Create;
739begin
740 Format := nil;
741 Enabled := True;
742 Categories := TAcronymCategories.Create;
743 Categories.OwnsObjects := False;
744end;
745
746destructor TImportSource.Destroy;
747begin
748 FreeAndNil(Categories);
749 inherited Destroy;
750end;
751
752{ TAcronymEntry }
753
754constructor TAcronymEntry.Create;
755begin
756 Categories := TStringList.Create;
757end;
758
759destructor TAcronymEntry.Destroy;
760begin
761 FreeAndNil(Categories);
762 inherited Destroy;
763end;
764
765{ TAcronymMeanings }
766
767procedure TAcronymMeanings.UpdateIds;
768var
769 LastId: Integer;
770 I: Integer;
771begin
772 // Get highest used ID
773 LastId := 0;
774 for I := 0 to Count - 1 do begin
775 if TAcronymMeaning(Items[I]).Id > LastId then LastId := TAcronymMeaning(Items[I]).Id;
776 end;
777 // Add ID to new items without ID
778 for I := 0 to Count - 1 do begin
779 if TAcronymMeaning(Items[I]).Id = 0 then begin
780 Inc(LastId);
781 TAcronymMeaning(Items[I]).Id := LastId;
782 end;
783 end;
784end;
785
786procedure TAcronymMeanings.SaveToNode(Node: TDOMNode);
787var
788 I: Integer;
789 NewNode2: TDOMNode;
790begin
791 UpdateIds;
792 for I := 0 to Count - 1 do
793 with TAcronymMeaning(Items[I]) do begin
794 NewNode2 := Node.OwnerDocument.CreateElement('Meaning');
795 Node.AppendChild(NewNode2);
796 SaveToNode(NewNode2);
797 end;
798end;
799
800procedure TAcronymMeanings.LoadFromNode(Node: TDOMNode);
801var
802 Node2: TDOMNode;
803 NewItem: TAcronymMeaning;
804begin
805 Count := 0;
806 Node2 := Node.FirstChild;
807 while Assigned(Node2) and (Node2.NodeName = 'Meaning') do begin
808 NewItem := TAcronymMeaning.Create;
809 NewItem.Acronym := Acronym;
810 NewItem.LoadFromNode(Node2);
811 Add(NewItem);
812 Node2 := Node2.NextSibling;
813 end;
814 UpdateIds;
815end;
816
817function TAcronymMeanings.SearchByName(Name: string): TAcronymMeaning;
818var
819 I: Integer;
820begin
821 I := 0;
822 while (I < Count) and (TAcronymMeaning(Items[I]).Name <> Name) do Inc(I);
823 if I < Count then Result := TAcronymMeaning(Items[I])
824 else Result := nil;
825end;
826
827function TAcronymMeanings.AddMeaning(Name: string): TAcronymMeaning;
828begin
829 Result := TAcronymMeaning.Create;
830 Result.Name := Name;
831 Add(Result);
832end;
833
834{ TAcronymMeaning }
835
836procedure TAcronymMeaning.SaveToNode(Node: TDOMNode);
837var
838 NewNode: TDOMNode;
839begin
840 WriteString(Node, 'Name', Name);
841 WriteString(Node, 'Description', Description);
842 WriteString(Node, 'Language', Language);
843
844 NewNode := Node.OwnerDocument.CreateElement('Categories');
845 Node.AppendChild(NewNode);
846 Categories.SaveRefToNode(NewNode);
847end;
848
849procedure TAcronymMeaning.LoadFromNode(Node: TDOMNode);
850var
851 Node2: TDOMNode;
852 I: Integer;
853begin
854 Name := ReadString(Node, 'Name', '');
855 Description := ReadString(Node, 'Description', '');
856 Language := ReadString(Node, 'Language', '');
857
858 Categories.Db := Acronym.Db;
859 Node2 := Node.FindNode('Categories');
860 if Assigned(Node2) then begin
861 Categories.LoadRefFromNode(Node2);
862
863 // Add reverse references
864 for I := 0 to Categories.Count - 1 do
865 TAcronymCategory(Categories[I]).AcronymMeanings.Add(Self);
866 end;
867end;
868
869constructor TAcronymMeaning.Create;
870begin
871 Categories := TAcronymCategories.Create(False);
872end;
873
874destructor TAcronymMeaning.Destroy;
875var
876 I: Integer;
877begin
878 for I := 0 to Categories.Count - 1 do
879 TAcronymCategory(Categories[I]).AcronymMeanings.Remove(Self);
880 FreeAndNil(Categories);
881 inherited Destroy;
882end;
883
884{ TAcronyms }
885
886procedure TAcronyms.SaveToNode(Node: TDOMNode);
887var
888 I: Integer;
889 NewNode2: TDOMNode;
890begin
891 for I := 0 to Count - 1 do
892 with TAcronym(Items[I]) do begin
893 NewNode2 := Node.OwnerDocument.CreateElement('Acronym');
894 Node.AppendChild(NewNode2);
895 SaveToNode(NewNode2);
896 end;
897end;
898
899procedure TAcronyms.LoadFromNode(Node: TDOMNode);
900var
901 Node2: TDOMNode;
902 NewItem: TAcronym;
903begin
904 Count := 0;
905 Node2 := Node.FirstChild;
906 while Assigned(Node2) and (Node2.NodeName = 'Acronym') do begin
907 NewItem := TAcronym.Create;
908 NewItem.Db := Db;
909 NewItem.LoadFromNode(Node2);
910 Add(NewItem);
911 Node2 := Node2.NextSibling;
912 end;
913end;
914
915function TAcronyms.SearchByName(Name: string): TAcronym;
916var
917 I: Integer;
918begin
919 I := 0;
920 while (I < Count) and (TAcronym(Items[I]).Name <> Name) do Inc(I);
921 if I < Count then Result := TAcronym(Items[I])
922 else Result := nil;
923end;
924
925function TAcronyms.AddAcronym(Name: string): TAcronym;
926begin
927 Result := TAcronym.Create;
928 Result.Name := Name;
929 Add(Result);
930end;
931
932{ TAcronymCategories }
933
934procedure TAcronymCategories.UpdateIds;
935var
936 LastId: Integer;
937 I: Integer;
938begin
939 // Get highest used ID
940 LastId := 0;
941 for I := 0 to Count - 1 do begin
942 if TAcronymCategory(Items[I]).Id > LastId then LastId := TAcronymCategory(Items[I]).Id;
943 end;
944 // Add ID to new items without ID
945 for I := 0 to Count - 1 do begin
946 if TAcronymCategory(Items[I]).Id = 0 then begin
947 Inc(LastId);
948 TAcronymCategory(Items[I]).Id := LastId;
949 end;
950 end;
951end;
952
953procedure TAcronymCategories.SaveToNode(Node: TDOMNode);
954var
955 I: Integer;
956 NewNode2: TDOMNode;
957begin
958 UpdateIds;
959 for I := 0 to Count - 1 do
960 with TAcronymCategory(Items[I]) do begin
961 NewNode2 := Node.OwnerDocument.CreateElement('Category');
962 Node.AppendChild(NewNode2);
963 SaveToNode(NewNode2);
964 end;
965end;
966
967procedure TAcronymCategories.LoadFromNode(Node: TDOMNode);
968var
969 Node2: TDOMNode;
970 NewItem: TAcronymCategory;
971begin
972 Count := 0;
973 Node2 := Node.FirstChild;
974 while Assigned(Node2) and (Node2.NodeName = 'Category') do begin
975 NewItem := TAcronymCategory.Create;
976 NewItem.LoadFromNode(Node2);
977 Add(NewItem);
978 Node2 := Node2.NextSibling;
979 end;
980 UpdateIds;
981end;
982
983procedure TAcronymCategories.SaveRefToNode(Node: TDOMNode);
984var
985 I: Integer;
986 NewNode: TDOMNode;
987begin
988 for I := 0 to Count - 1 do begin
989 NewNode := Node.OwnerDocument.CreateElement('Category');
990 Node.AppendChild(NewNode);
991 WriteInteger(NewNode, 'Id', TAcronymCategory(Items[I]).Id);
992 end;
993end;
994
995procedure TAcronymCategories.LoadRefFromNode(Node: TDOMNode);
996var
997 Node2: TDOMNode;
998 Id: Integer;
999 Category: TAcronymCategory;
1000begin
1001 Node2 := Node.FirstChild;
1002 while Assigned(Node2) and (Node2.NodeName = 'Category') do begin
1003 Id := ReadInteger(Node2, 'Id', 0);
1004 Category := Db.Categories.SearchById(Id);
1005 if Assigned(Category) then begin
1006 Add(Category);
1007 end;
1008 Node2 := Node2.NextSibling;
1009 end;
1010end;
1011
1012function TAcronymCategories.SearchByName(Name: string): TAcronymCategory;
1013var
1014 I: Integer;
1015begin
1016 I := 0;
1017 while (I < Count) and (TAcronymCategory(Items[I]).Name <> Name) do Inc(I);
1018 if I < Count then Result := TAcronymCategory(Items[I])
1019 else Result := nil;
1020end;
1021
1022function TAcronymCategories.SearchById(Id: Integer): TAcronymCategory;
1023var
1024 I: Integer;
1025begin
1026 I := 0;
1027 while (I < Count) and (TAcronymCategory(Items[I]).Id <> Id) do Inc(I);
1028 if I < Count then Result := TAcronymCategory(Items[I])
1029 else Result := nil;
1030end;
1031
1032function TAcronymCategories.AddContext(Name: string): TAcronymCategory;
1033begin
1034 Result := TAcronymCategory.Create;
1035 Result.Name := Name;
1036 Add(Result);
1037end;
1038
1039procedure TAcronymCategories.AssignToStrings(Strings: TStrings);
1040var
1041 I: Integer;
1042begin
1043 Strings.Clear;
1044 for I := 0 to Count - 1 do
1045 Strings.AddObject(TAcronymCategory(Items[I]).Name, Items[I]);
1046end;
1047
1048procedure TAcronymCategories.AssignFromStrings(Strings: TStrings);
1049var
1050 I: Integer;
1051begin
1052 Clear;
1053 for I := 0 to Strings.Count - 1 do begin
1054 Add(TAcronymCategory(Strings.Objects[I]));
1055 end;
1056end;
1057
1058function TAcronymCategories.GetString: string;
1059var
1060 I: Integer;
1061begin
1062 Result := '';
1063 for I := 0 to Count - 1 do
1064 Result := Result + TAcronymCategory(Items[I]).Name + ',';
1065 System.Delete(Result, Length(Result), 1);
1066end;
1067
1068
1069{ TAcronym }
1070
1071procedure TAcronym.SaveToNode(Node: TDOMNode);
1072var
1073 NewNode: TDOMNode;
1074begin
1075 WriteString(Node, 'Name', Name);
1076
1077 NewNode := Node.OwnerDocument.CreateElement('Meanings');
1078 Node.AppendChild(NewNode);
1079 Meanings.SaveToNode(NewNode);
1080end;
1081
1082procedure TAcronym.LoadFromNode(Node: TDOMNode);
1083var
1084 NewNode: TDOMNode;
1085begin
1086 Name := ReadString(Node, 'Name', '');
1087
1088 NewNode := Node.FindNode('Meanings');
1089 if Assigned(NewNode) then
1090 Meanings.LoadFromNode(NewNode);
1091end;
1092
1093constructor TAcronym.Create;
1094begin
1095 Meanings := TAcronymMeanings.Create;
1096 Meanings.Acronym := Self;
1097end;
1098
1099destructor TAcronym.Destroy;
1100begin
1101 FreeAndNil(Meanings);
1102 inherited Destroy;
1103end;
1104
1105{ TAcronymCategory }
1106
1107procedure TAcronymCategory.SaveToNode(Node: TDOMNode);
1108begin
1109 WriteString(Node, 'Name', Name);
1110 WriteInteger(Node, 'Id', Id);
1111end;
1112
1113procedure TAcronymCategory.LoadFromNode(Node: TDOMNode);
1114begin
1115 Name := ReadString(Node, 'Name', '');
1116 Id := ReadInteger(Node, 'Id', 0);
1117end;
1118
1119constructor TAcronymCategory.Create;
1120begin
1121 AcronymMeanings := TAcronymMeanings.Create(False);
1122end;
1123
1124destructor TAcronymCategory.Destroy;
1125var
1126 I: Integer;
1127begin
1128 for I := 0 to AcronymMeanings.Count - 1 do
1129 TAcronymMeaning(AcronymMeanings[I]).Categories.Remove(Self);
1130 FreeAndNil(AcronymMeanings);
1131 inherited Destroy;
1132end;
1133
1134{ TAcronymDb }
1135
1136constructor TAcronymDb.Create;
1137begin
1138 Sources := TAcronymSources.Create;
1139 Acronyms := TAcronyms.Create;
1140 Acronyms.Db := Self;
1141 Categories := TAcronymCategories.Create;
1142 ImportSources := TImportSources.Create;
1143 ImportSources.AcronymDb := Self;
1144 ImportFormats := TImportFormats.Create;
1145end;
1146
1147destructor TAcronymDb.Destroy;
1148begin
1149 FreeAndNil(ImportFormats);
1150 FreeAndNil(ImportSources);
1151 FreeAndNil(Sources);
1152 FreeAndNil(Acronyms);
1153 FreeAndNil(Categories);
1154 inherited Destroy;
1155end;
1156
1157procedure TAcronymDb.LoadFromFile(FileName: string);
1158var
1159 NewNode: TDOMNode;
1160 Doc: TXMLDocument;
1161 RootNode: TDOMNode;
1162begin
1163 if ExtractFileExt(FileName) = '.csv' then begin
1164 LoadFromFileCSV(FileName);
1165 Exit;
1166 end;
1167 Self.FileName := FileName;
1168 ReadXMLFile(Doc, FileName);
1169 with Doc do try
1170 if Doc.DocumentElement.NodeName <> 'AcronymDecoderProject' then
1171 raise Exception.Create(SWrongFileFormat);
1172 RootNode := Doc.DocumentElement;
1173 with RootNode do begin
1174 NewNode := FindNode('Categories');
1175 if Assigned(NewNode) then
1176 Categories.LoadFromNode(NewNode);
1177
1178 // Load acronyms after categories because of references
1179 NewNode := FindNode('Acronyms');
1180 if Assigned(NewNode) then
1181 Acronyms.LoadFromNode(NewNode);
1182
1183 NewNode := FindNode('ImportFormats');
1184 if Assigned(NewNode) then
1185 ImportFormats.LoadFromNode(NewNode);
1186
1187 NewNode := FindNode('ImportSources');
1188 if Assigned(NewNode) then
1189 ImportSources.LoadFromNode(NewNode);
1190 end;
1191 finally
1192 Doc.Free;
1193 end;
1194end;
1195
1196procedure TAcronymDb.SaveToFile(FileName: string);
1197var
1198 NewNode: TDOMNode;
1199 Doc: TXMLDocument;
1200 RootNode: TDOMNode;
1201begin
1202 if ExtractFileExt(FileName) = '.csv' then begin
1203 SaveToFileCSV(FileName);
1204 Exit;
1205 end;
1206 Self.FileName := FileName;
1207 Doc := TXMLDocument.Create;
1208 with Doc do try
1209 RootNode := CreateElement('AcronymDecoderProject');
1210 AppendChild(RootNode);
1211 with RootNode do begin
1212 NewNode := OwnerDocument.CreateElement('Categories');
1213 AppendChild(NewNode);
1214 Categories.SaveToNode(NewNode);
1215
1216 // Save acronyms after categories because of references
1217 NewNode := OwnerDocument.CreateElement('Acronyms');
1218 AppendChild(NewNode);
1219 Acronyms.SaveToNode(NewNode);
1220
1221 NewNode := OwnerDocument.CreateElement('ImportFormats');
1222 AppendChild(NewNode);
1223 ImportFormats.SaveToNode(NewNode);
1224
1225 NewNode := OwnerDocument.CreateElement('ImportSources');
1226 AppendChild(NewNode);
1227 ImportSources.SaveToNode(NewNode);
1228 end;
1229 ForceDirectories(ExtractFileDir(FileName));
1230 WriteXMLFile(Doc, FileName);
1231 finally
1232 Doc.Free;
1233 end;
1234 Modified := False;
1235end;
1236
1237procedure TAcronymDb.LoadFromFileCSV(FileName: string);
1238var
1239 F: TStringList;
1240 Line: TStringList;
1241 CategoryStrings: TStringList;
1242 NewAcronym: TAcronym;
1243 NewMeaning: TAcronymMeaning;
1244 I: Integer;
1245 J: Integer;
1246 AcronymCategory: TAcronymCategory;
1247begin
1248 Self.FileName := FileName;
1249 Acronyms.Clear;
1250 F := TStringList.Create;
1251 Line := TStringList.Create;
1252 Line.StrictDelimiter := True;
1253 CategoryStrings := TStringList.Create;
1254 CategoryStrings.Delimiter := ';';
1255 try
1256 F.LoadFromFile(FileName);
1257 for I := 0 to F.Count - 1 do begin
1258 Line.CommaText := F[I];
1259 NewAcronym := Acronyms.SearchByName(Line[0]);
1260 if not Assigned(NewAcronym) then begin
1261 NewAcronym := TAcronym.Create;
1262 NewAcronym.Name := Line[0];
1263 Acronyms.Add(NewAcronym);
1264 end;
1265 NewMeaning := NewAcronym.Meanings.SearchByName(Line[1]);
1266 if not Assigned(NewMeaning) then begin
1267 NewMeaning := TAcronymMeaning.Create;
1268 NewMeaning.Name := Line[1];
1269 NewMeaning.Acronym := NewAcronym;
1270 NewAcronym.Meanings.Add(NewMeaning);
1271 end;
1272 CategoryStrings.DelimitedText := Line[2];
1273 for J := 0 to CategoryStrings.Count - 1 do begin
1274 AcronymCategory := Categories.SearchByName(CategoryStrings[J]);
1275 if not Assigned(AcronymCategory) then begin
1276 AcronymCategory := TAcronymCategory.Create;
1277 AcronymCategory.Name := CategoryStrings[J];
1278 Categories.Add(AcronymCategory);
1279 end;
1280 NewMeaning.Categories.Add(AcronymCategory);
1281 AcronymCategory.AcronymMeanings.Add(NewMeaning);
1282 end;
1283 end;
1284 finally
1285 F.Free;
1286 Line.Free;
1287 CategoryStrings.Free;
1288 end;
1289 Modified := False;
1290end;
1291
1292procedure TAcronymDb.SaveToFileCSV(FileName: string);
1293var
1294 I: Integer;
1295 J: Integer;
1296 K: Integer;
1297 F: TStringList;
1298 Line: TStringList;
1299 Context: TStringList;
1300begin
1301 Self.FileName := FileName;
1302 F := TStringList.Create;
1303 Line := TStringList.Create;
1304 Line.StrictDelimiter := True;
1305 Context := TStringList.Create;
1306 Context.Delimiter := ';';
1307 try
1308 Line.Clear;
1309 for I := 0 to Acronyms.Count - 1 do
1310 with TAcronym(Acronyms[I]) do begin
1311 for K := 0 to Meanings.Count - 1 do
1312 with TAcronymMeaning(Meanings[K]) do begin
1313 Line.Clear;
1314 Line.Add(Acronym.Name);
1315 Line.Add(Name);
1316 Context.Clear;
1317 for J := 0 to Categories.Count - 1 do
1318 Context.Add(TAcronymCategory(Categories[J]).Name);
1319 Line.Add(Context.DelimitedText);
1320 F.Add(Line.CommaText);
1321 end;
1322 end;
1323 F.SaveToFile(FileName);
1324 finally
1325 F.Free;
1326 Line.Free;
1327 Context.Free;
1328 end;
1329 Modified := False;
1330end;
1331
1332procedure TAcronymDb.FilterList(AName: string; Items: TAcronymMeanings);
1333var
1334 I: Integer;
1335 J: Integer;
1336begin
1337 AName := LowerCase(AName);
1338 Items.Clear;
1339 for I := 0 to Acronyms.Count - 1 do
1340 with TAcronym(Acronyms[I]) do begin
1341 for J := 0 to Meanings.Count - 1 do
1342 with TAcronymMeaning(Meanings[J]) do begin
1343 if (AName = '') or (Pos(AName, LowerCase(TAcronym(Acronyms[I]).Name)) > 0)
1344 or (Pos(AName, LowerCase(Name)) > 0) then Items.Add(TAcronymMeaning(Meanings[J]))
1345 end;
1346 end;
1347end;
1348
1349function TAcronymDb.AddAcronym(AcronymName, MeaningName: string): TAcronymMeaning;
1350var
1351 Acronym: TAcronym;
1352 Meaning: TAcronymMeaning;
1353begin
1354 Acronym := Acronyms.SearchByName(AcronymName);
1355 if not Assigned(Acronym) then begin
1356 Acronym := TAcronym.Create;
1357 Acronym.Name := AcronymName;
1358 Acronyms.Add(Acronym);
1359 end;
1360 Meaning := Acronym.Meanings.SearchByName(MeaningName);
1361 if not Assigned(Meaning) then begin
1362 Meaning := TAcronymMeaning.Create;
1363 Meaning.Name := MeaningName;
1364 Meaning.Acronym := Acronym;
1365 Acronym.Meanings.Add(Meaning);
1366 end;
1367 Result := Meaning;
1368 Modified := True;
1369end;
1370
1371procedure TAcronymDb.RemoveMeaning(Meaning: TAcronymMeaning);
1372var
1373 Acronym: TAcronym;
1374begin
1375 Acronym := Meaning.Acronym;
1376 Acronym.Meanings.Remove(Meaning);
1377 if Acronym.Meanings.Count = 0 then
1378 Acronyms.Remove(Acronym);
1379 Modified := True;
1380end;
1381
1382procedure TAcronymDb.RemoveAcronym(AcronymName, MeaningName: string);
1383var
1384 Acronym: TAcronym;
1385 Meaning: TAcronymMeaning;
1386begin
1387 Acronym := Acronyms.SearchByName(AcronymName);
1388 if Assigned(Acronym) then begin
1389 Meaning := Acronym.Meanings.SearchByName(MeaningName);
1390 if Assigned(Meaning) then RemoveMeaning(Meaning);
1391 end;
1392end;
1393
1394procedure TAcronymDb.AssignToList(List: TListObject);
1395var
1396 I: Integer;
1397 J: Integer;
1398begin
1399 List.Clear;
1400 for I := 0 to Acronyms.Count - 1 do
1401 with TAcronym(Acronyms[I]) do begin
1402 for J := 0 to Meanings.Count - 1 do
1403 with TAcronymMeaning(Meanings[J]) do begin
1404 List.Add(TAcronymMeaning(Meanings[J]))
1405 end;
1406 end;
1407end;
1408
1409end.
1410
Note: See TracBrowser for help on using the repository browser.