6 Contnrs, Controls, Classes, SysUtils, Dialogs, Forms, HttpThread, BottleDef,
7 DateUtils, SsParser, XDOM_2_3_J3, Graphics, SppList;
11 TLogType = (ltBottle, ltSystemLog);
12 TLogState = (lsUnopened, lsPlaying, lsOpened);
14 THasURL = (huUndefined, huYes, huNo);
16 TLogItem = class(TPersistent)
28 procedure SetChannel(const Value: String);
29 procedure SetLogType(const Value: TLogType);
30 procedure SetMID(const Value: String);
31 procedure SetScript(const Value: String);
32 procedure SetLogTime(const Value: TDateTime);
33 procedure SetGhost(const Value: String);
34 procedure SetVotes(const Value: Integer);
35 procedure SetAgreements(const Value: Integer);
36 procedure SetState(const Value: TLogState);
37 procedure SetHasURL(const Value: THasURL);
39 constructor Create(LogType: TLogType; const MID, Channel, Script,
40 Ghost: String; LogTime: TDateTime); overload;
41 constructor Create(Source: TLogItem); overload;
42 property LogType: TLogType read FLogType write SetLogType;
43 property MID: String read FMID write SetMID;
44 property Channel: String read FChannel write SetChannel;
45 property LogTime: TDateTime read FLogTime write SetLogTime;
46 property Script: String read FScript write SetScript;
47 property Ghost: String read FGhost write SetGhost;
48 property Votes: Integer read FVotes write SetVotes;
49 property Agrees: Integer read FAgreements write SetAgreements;
50 property State: TLogState read FState write SetState;
51 property HasURL: THasURL read FHasURL write SetHasURL;
52 procedure Assign(Source: TPersistent); override;
55 TBottleLogSortType = (stLogTime, stChannel, stGhost, stScript, stVote, stAgree);
56 TBottleLogLoadFailureEvent = procedure(Sender: TObject; const Message: String) of object;
57 TBottleLogHTMLOutputWork = procedure(Sender: TObject; const Count: integer;
58 var Canceled: boolean) of object;
60 EXMLFileOpenException = class(Exception);
62 TBottleLogDownLoadCondition = packed record
72 TLogXMLThread = class(TThread)
76 FOnLoadFailure: TBottleLogLoadFailureEvent;
77 FOnLoaded: TNotifyEvent;
78 FLoadFailureMessage: String;
79 procedure SetOnLoaded(const Value: TNotifyEvent);
80 procedure SetOnLoadFailure(const Value: TBottleLogLoadFailureEvent);
82 procedure Execute; override;
84 procedure DoLoadFailure;
86 property OnLoaded: TNotifyEvent read FOnLoaded write SetOnLoaded;
87 property OnLoadFailure: TBottleLogLoadFailureEvent
88 read FOnLoadFailure write SetOnLoadFailure;
89 property List: TObjectList read FList;
90 constructor Create(FileName: String);
91 destructor Destroy; override;
94 THTMLOutputUseColor = (ucUse, ucNoUse);
95 THTMLOutputImageType = (itNone, itBMP, itPNG, itJPG);
96 THTMLOutputRange = (orAll, orUpward, orSelected);
98 THTMLOutputOptions = record
100 UseColor: THTMLOutputUseColor;
101 ImageType: THTMLOutputImageType;
104 TBottleLogList = class(TObjectList)
106 FOnLoaded: TNotifyEvent;
107 FHttpThread: THTTPDownloadThread;
108 FXMLThread: TLogXMLThread;
111 FOnLoadFailure: TBottleLogLoadFailureEvent;
112 FOldSortColumn: TBottleLogSortType; //
\83\8d\83O
\91\8b
113 FOldSortDesc: boolean; //
\83\8d\83O
\91\8b
114 FSelectedIndex: integer;
115 FOnLoadWork: TNotifyEvent; //
\83\8d\83O
\91\8b
116 FImagePath: String; // HTML
\8fo
\97Í
\8e\9e\82ÌIMG
\83^
\83O
\82Ì
\83p
\83X(
\91\8a\91Î
\82Ü
\82½
\82Í
\90â
\91Î
\83p
\83X)
117 FImageFiles: TStringList;
118 FOnHTMLOutputWork: TBottleLogHTMLOutputWork; //
\8fd
\95¡
\89æ
\91\9c\8fo
\97Í
\82µ
\82È
\82¢
\82½
\82ß
\82Ì
\83`
\83F
\83b
\83J
119 FLogModified: boolean; //
\83\8a\83X
\83g
\82ª
\95Ï
\8dX
\82³
\82ê
\82½
\82©
\81H
121 function GetBottles(Index: integer): TLogItem;
122 procedure SetOnLoaded(const Value: TNotifyEvent);
123 procedure HttpSuccess(Sender: TObject);
124 procedure HttpFailure(Sender: TObject);
125 procedure HttpWork(Sender: TObject; LoadBytes: integer);
126 procedure XMLLoaded(Sener: TObject);
127 procedure XMLLoadFailure(Sender: TObject; const Message: String);
128 procedure SetTitle(const Value: String);
129 procedure SetOnLoadFailure(const Value: TBottleLogLoadFailureEvent);
130 procedure SetSelectedIndex(const Value: integer);
131 procedure SetOnLoadWork(const Value: TNotifyEvent);
132 procedure DoLoadFailure(const ErrorMessage: String);
133 function ColorToHex(const Col: TColor): String;
134 procedure PrintHTMLBottle(Strs: TStringList; Bottle: TLogItem;
135 SsParser: TSsParser; const Options: THTMLOutputOptions);
136 function PrintSurfaceImage(Strs: TStringList; const Ghost: String; ID: integer;
137 const Options: THTMLOutputOptions): boolean;
138 procedure SetOnHTMLOutputWork(const Value: TBottleLogHTMLOutputWork);
139 procedure SetLogModified(const Value: boolean);
141 constructor Create(const Title: String);
142 destructor Destroy; override;
143 procedure SortBottles(LogSortType: TBottleLogSortType);
144 function Bottle(MID: String): TLogItem;
145 property Bottles[Index: integer]: TLogItem read GetBottles;
146 procedure LoadFromWeb(const Cond: TBottleLogDownloadCondition);
147 property Title: String read FTitle write SetTitle;
148 procedure LoadFromStream(Stream: TStream);
149 property OnLoaded: TNotifyEvent read FOnLoaded write SetOnLoaded;
150 property OnLoadWork: TNotifyEvent read FOnLoadWork write SetOnLoadWork;
151 property OnLoadFailure: TBottleLogLoadFailureEvent read FOnLoadFailure write SetOnLoadFailure;
152 property SelectedIndex: integer read FSelectedIndex write SetSelectedIndex;
153 procedure AddScriptLog(const Script, Channel, MID, Ghost: String;
154 const LogTime: TDateTime; const Vote, Agree: integer);
155 procedure AddSystemLog(const MessageString: String);
156 procedure SaveToText(const FileName: String);
157 procedure SaveToSstpLog(const FileName: String;
158 const WithChannel: boolean = false);
159 procedure SaveToXMLFile(const FileName: String);
160 procedure LoadFromXMLFile(const FileName: String);
161 procedure SaveToHTML(const FileName: String;
162 const Options: THTMLOutputOptions; SsParser: TSsParser);
163 procedure ExtractUniqueChannels(Target: TStrings);
164 procedure ExtractUniqueGhosts(Target: TStrings);
165 property OnHTMLOutputWork: TBottleLogHTMLOutputWork read FOnHTMLOutputWork write SetOnHTMLOutputWork;
166 property LogModified: boolean read FLogModified write SetLogModified;
170 ASortType: TBottleLogSortType; //LogCompare
\8aÖ
\90\94\82©
\82ç
\8c©
\82¦
\82é
\82æ
\82¤
\82É
\88ê
\8e\9e\91Þ
\94ð
\97p
173 function LogCompare(Item1, Item2: Pointer): integer;
176 ////////////////////////////////////////////////////////////////////////////////
181 function LogCompare(Item1, Item2: Pointer): Integer;
183 Log1, Log2: TLogItem;
185 Log1 := TLogItem(Item1);
186 Log2 := TLogItem(Item2);
190 Result := AnsiCompareStr(Log2.MID, Log1.MID);
193 Result := AnsiCompareStr(Log1.Channel, Log2.Channel);
196 Result := AnsiCompareStr(Log1.Ghost, Log2.Ghost);
199 Result := AnsiCompareStr(Log1.Script, Log2.Script);
202 Result := Log2.Votes - Log1.Votes;
205 Result := Log2.Agrees - Log1.Agrees;
208 if ASortDesc then Result := -Result; //
\8f¸
\8f\87
213 constructor TLogItem.Create(LogType: TLogType; const MID, Channel, Script,
214 Ghost: String; LogTime: TDateTime);
216 Self.LogType := LogType;
218 Self.Script := Script;
219 Self.Channel := Channel;
221 Self.LogTime := LogTime;
222 Self.State := lsUnopened;
225 procedure TLogItem.SetChannel(const Value: String);
230 procedure TLogItem.SetLogType(const Value: TLogType);
235 procedure TLogItem.SetMID(const Value: String);
240 procedure TLogItem.SetScript(const Value: String);
245 procedure TLogItem.SetLogTime(const Value: TDateTime);
250 procedure TLogItem.SetAgreements(const Value: Integer);
252 FAgreements := Value;
255 procedure TLogItem.SetVotes(const Value: Integer);
260 procedure TLogItem.SetGhost(const Value: String);
266 procedure TLogItem.SetState(const Value: TLogState);
271 procedure TLogItem.Assign(Source: TPersistent);
274 if not (Source is TLogItem) then
277 Src := Source as TLogItem;
278 self.FScript := Src.FScript;
279 self.FChannel := Src.FChannel;
280 self.FMID := Src.FMID;
281 self.FLogTime := Src.FLogTime;
282 self.FLogType := Src.FLogType;
283 self.FGhost := Src.FGhost;
284 self.FVotes := Src.FVotes;
285 self.FAgreements := Src.FAgreements;
286 self.FState := Src.FState;
287 self.FHasURL := Src.FHasURL;
291 constructor TLogItem.Create(Source: TLogItem);
296 procedure TLogItem.SetHasURL(const Value: THasURL);
303 procedure TBottleLogList.AddScriptLog(const Script, Channel, MID,
304 Ghost: String; const LogTime: TDateTime; const Vote, Agree: integer);
305 var LogItem: TLogItem;
307 LogItem := TLogItem.Create(ltBottle, MID, Channel, Script, Ghost, LogTime);
308 LogItem.FVotes := Vote;
309 LogItem.FAgreements := Agree;
318 procedure TBottleLogList.AddSystemLog(const MessageString: String);
319 var LogItem: TLogItem;
321 LogItem := TLogItem.Create(ltSystemLog, '', '', MessageString, '', Now());
330 function TBottleLogList.Bottle(MID: String): TLogItem;
334 for i := 0 to Count-1 do
335 if (Items[i] as TLogItem).MID = MID then begin
336 Result := Items[i] as TLogItem;
341 function TBottleLogList.ColorToHex(const Col: TColor): String;
346 RGB := ColorToRGB(Col);
348 G := (RGB and $FF00) shr 8;
349 B := (RGB and $FF0000) shr 16;
350 RGB := (R shl 16) or (G shl 8) or B;
351 Result := '#' + IntToHex(RGB, 6);
354 constructor TBottleLogList.Create(const Title: String);
359 FSelectedIndex := -1; //
\91I
\91ð
\82³
\82ê
\82Ä
\82¢
\82È
\82¢
360 FLogModified := false; //
\95Ï
\8dX
\96³
\82µ
363 destructor TBottleLogList.Destroy;
366 // FHttpThread
\82Í
\8e©
\95ª
\82ðFree
\82·
\82é
\81u
\91O
\81v
\82ÉSynchronize
\82Å
\8eQ
\8fÆ
\82ª
\8dí
\8f\9c\82³
\82ê
\82é
\82Ì
\82Å
\81A
367 // FHttpThread <> nil
\82È
\82ç
\8eÀ
\91Ì
\82ª
\91¶
\8dÝ
\82·
\82é
\82±
\82Æ
\82Í
\8am
\8eÀ
\82Å
\82 \82é
\81B
368 if FHttpThread <> nil then begin
369 FHttpThread.OnSuccess := nil;
370 FHttpThread.OnConnectionFailed := nil;
374 procedure TBottleLogList.DoLoadFailure(const ErrorMessage: String);
377 self.AddSystemLog(ErrorMessage);
378 if Assigned(FOnLoadFailure) then FOnLoadFailure(self, ErrorMessage);
381 procedure TBottleLogList.ExtractUniqueChannels(Target: TStrings);
384 //
\82±
\82Ì
\83\8d\83O
\92\86\82Ì
\83`
\83\83\83\93\83l
\83\8b\82ð
\8eæ
\82è
\8fo
\82·
385 // TStrings
\82Ì
\8eÀ
\91\95\82ÍTHashedStringList
\90\84\8f§
386 for i := 0 to Count-1 do
387 if Target.IndexOf(Bottles[i].Channel) < 0 then
388 Target.Add(Bottles[i].Channel);
391 procedure TBottleLogList.ExtractUniqueGhosts(Target: TStrings);
394 //
\82±
\82Ì
\83\8d\83O
\92\86\82Ì
\83S
\81[
\83X
\83g
\82ð
\8eæ
\82è
\8fo
\82·
395 // TStrings
\82Ì
\8eÀ
\91\95\82ÍTHashedStringList
\90\84\8f§
396 for i := 0 to Count-1 do
397 if Target.IndexOf(Bottles[i].Ghost) < 0 then
398 Target.Add(Bottles[i].Ghost);
401 function TBottleLogList.GetBottles(Index: integer): TLogItem;
403 Result := Items[Index] as TLogItem;
406 procedure TBottleLogList.HttpFailure(Sender: TObject);
408 if Assigned(FOnLoadFailure) then
409 DoLoadFailure('
\83T
\81[
\83o
\82Ì
\90Ú
\91±
\82É
\8e¸
\94s
\82µ
\82Ü
\82µ
\82½');
412 procedure TBottleLogList.HttpSuccess(Sender: TObject);
413 var Stream: TStringStream;
414 StrList: TStringList;
416 Stream := TStringStream.Create(FHttpThread.RecvString);
418 StrList := TStringList.Create;
420 StrList.Text := Stream.DataString;
421 if StrList[0] <> 'Result: OK' then begin
422 if Assigned(FOnLoadFailure) then
423 DoLoadFailure('
\83T
\81[
\83o
\82ª
\83G
\83\89\81[
\82ð
\95Ô
\82µ
\82Ü
\82µ
\82½'#13#10 + Stream.DataString);
425 while StrList.Count > 0 do
426 if StrList[0] <> '' then StrList.Delete(0) else Break; //
\83w
\83b
\83_
\81[
\82ð
\8dí
\8f\9c\82·
\82é
427 if StrList.Count > 0 then StrList.Delete(0); //
\83w
\83b
\83_
\81[
\8cã
\82Ì
\8bó
\8ds
\8dí
\8f\9c
428 Stream.Seek(0, soFromBeginning);
429 Stream.Size := Length(StrList.Text);
430 Stream.WriteString(StrList.Text);
431 Stream.Seek(0, soFromBeginning);
432 LoadFromStream(Stream);
439 // nil
\82Å
\82È
\82¢
\8fê
\8d\87\82É
\82Í
\8eÀ
\91Ì
\82ª
\91¶
\8dÝ
\82·
\82é
\82±
\82Æ
\82ð
\8am
\8eÀ
\82É
\82·
\82é
440 //
\82½
\82¾
\82µ nil
\82¾
\82©
\82ç
\82Æ
\82¢
\82Á
\82Ä
\8eÀ
\91Ì
\82ª
\91¶
\8dÝ
\82µ
\82È
\82¢
\82Æ
\82Í
\8cÀ
\82ç
\82È
\82¢(FreeOnTerminate
\82Ì
\82½
\82ß)
445 procedure TBottleLogList.HttpWork(Sender: TObject; LoadBytes: integer);
448 AddSystemLog(Format('
\83_
\83E
\83\93\83\8d\81[
\83h
\92\86\82Å
\82· - %4d KB', [LoadBytes div 1024]));
449 FLoadBytes := LoadBytes;
450 if Assigned(FOnLoadWork) then FOnLoadWork(self);
453 procedure TBottleLogList.LoadFromStream(Stream: TStream);
455 SourceStream: TStringStream;
458 function S2D (const S: String): TDateTime;
460 Result := EncodeDateTime(
461 StrToInt(Copy(S, 1, 4)), StrToInt(Copy(S, 5, 2)), StrToInt(Copy(S, 7, 2)),
462 StrToInt(Copy(S, 9, 2)), StrToInt(Copy(S, 11, 2)), StrToInt(Copy(S, 13, 2)), 0);
469 SourceStream := TStringStream.Create('');
470 SourceStream.Seek(0, soFromBeginning);
471 SourceStream.CopyFrom(Stream, Stream.Size);
472 Source := TStringList.Create;
473 Source.Text := SourceStream.DataString;
475 if Source.Count = 0 then begin
476 DoLoadFailure('
\8ew
\92è
\8fð
\8c\8f\82Ì
\83\8d\83O
\82Í
\91¶
\8dÝ
\82µ
\82Ü
\82¹
\82ñ');
479 if Source[0] <> 'OK' then begin
482 while (i + 7) < Source.Count do begin
483 LogItem := TLogItem.Create(ltBottle, Source[i+1], Source[i+2],
484 Source[i+7], Source[i+3], S2D(Source[i]));
485 LogItem.Votes := StrToInt(Source[i+5]);
486 LogItem.Agrees := StrToInt(Source[i+6]);
487 LogItem.State := lsOpened;
496 On EConvertError do begin
497 DoLoadFailure('
\83T
\81[
\83o
\89\9e\93\9a\82Ì
\8c`
\8e®
\82ª
\95s
\90³
\82Å
\82·');
501 FOldSortColumn := stLogTime;
502 FOldSortDesc := false;
503 if Assigned(FOnLoaded) then FOnLoaded(Self);
506 procedure TBottleLogList.LoadFromWeb(const Cond: TBottleLogDownloadCondition);
510 AddSystemLog('
\83_
\83E
\83\93\83\8d\81[
\83h
\92\86\82Å
\82· -
\83T
\81[
\83o
\82©
\82ç
\89\9e\93\9a\91Ò
\82¿');
512 if Cond.IsRange then begin
513 Param := Format('year_lo=%d&month_lo=%d&day_lo=%d&year_hi=%d&month_hi=%d&day_hi=%d&',
514 [YearOf(DateLo), MonthOf(DateLo), DayOf(DateLo),
515 YearOf(DateHi), MonthOf(DateHi), DayOf(DateHi)]);
517 Param := Format('recent=%d&', [RecentCount]);
519 Param := Param + Format('minvote=%d&minagree=%d&channel=%s&sort=timedesc&delimiter=%%0D%%0A',
520 [MinVote, MinAgree, ParamsEncode(Channel)]);
522 FHttpThread := THTTPDownloadThread.Create(Pref.BottleServer, Pref.CgiFetchLog, Param);
523 if Pref.UseHttpProxy then begin
524 FHttpThread.ProxyServer := Pref.ProxyAddress;
525 FHttpThread.ProxyPort := Pref.ProxyPort;
527 FHttpThread.FreeOnTerminate := true;
528 FHttpThread.OnSuccess := HttpSuccess;
529 FHttpThread.OnConnectionFailed := HttpFailure;
530 FHttpThread.OnHttpWork := HttpWork;
536 procedure TBottleLogList.LoadFromXMLFile(const FileName: String);
539 AddSystemLog('
\83\8d\81[
\83h
\92\86...');
540 FXMLThread := TLogXMLThread.Create(FileName);
541 FXMLThread.FreeOnTerminate := true; //
\8f\9f\8eè
\82É
\8fÁ
\82¦
\82Ä
\82à
\82ç
\82¤
544 OnLoaded := XMLLoaded;
545 OnLoadFailure := XMLLoadFailure;
550 procedure TBottleLogList.PrintHTMLBottle(Strs: TStringList;
551 Bottle: TLogItem; SsParser: TSsParser; const Options: THTMLOutputOptions);
554 InScope1, InSync: boolean;
556 sur0, sur1, sur: integer;
562 if InSync then Cl := 'synchronized'
563 else if InScope1 then Cl := 'scope1'
565 if Options.ImageType = itNone then
569 Add(' <tr class="' + Cl + '">');
570 Add(' <td class="talk">' + XMLEntity(Talk) + '</td>');
575 //
\83`
\83\83\83\93\83l
\83\8b\83S
\81[
\83X
\83g
\91Î
\8dô
576 if Bottle.Ghost = '' then
577 if ChannelList.Channel[Bottle.Channel] <> nil then
578 Bottle.Ghost := ChannelList.Channel[Bottle.Channel].Ghost;
581 Add(' <tr class="' + Cl + '">');
582 Add(' <td class="surface">');
585 PrintSurfaceImage(Strs, Bottle.Ghost, Sur0, Options);
586 PrintSurfaceImage(Strs, Bottle.Ghost, Sur1, Options);
587 end else if InScope1 then
589 PrintSurfaceImage(Strs, Bottle.Ghost, Sur1, Options);
592 PrintSurfaceImage(Strs, Bottle.Ghost, Sur0, Options);
595 Add(' <td class="talk">' + Talk + '</td>');
600 end; // of sub-procedure TalkEnd
602 SsParser.EscapeInvalidMeta := false;
603 SsParser.LeaveEscape := false;
604 SsParser.InputString := Bottle.Script;
609 for i := 0 to SsParser.Count-1 do
610 case SsParser.MarkUpType[i] of
612 Talk := Talk + XMLEntity(SsParser.Str[i]);
615 Tag := SsParser.Str[i];
618 if InScope1 and not InSync then
621 end else if (Tag = '\u') then
623 if not InScope1 and not InSync then
626 end else if Tag = '\_s' then
629 InSync := not InSync;
630 end else if SsParser.Match(Tag, '\s%d') = 3 then
633 sur := Ord(Tag[3]) - Ord('0');
638 end else if InScope1 then
642 end else if (SsParser.Match(Tag, '\s[%D]') > 0) or (Tag = '\s[-1]') then
645 sur := StrToInt(SsParser.GetParam(Tag, 1));
650 end else if InScope1 then
654 end else if SsParser.Match(Tag, '\n') >= 2 then
657 Talk := Talk + '<br>';
658 end else if Tag = '\c' then
667 function TBottleLogList.PrintSurfaceImage(Strs: TStringList; const Ghost: String;
668 ID: integer; const Options: THTMLOutputOptions): boolean;
671 Path, Ext, Name: String;
674 if (ID < 0) or (Ghost = '') then
677 Name := Format('%s,%d.%s', [SafeFileName(Ghost), ID, Ext]);
678 if FImageFiles.IndexOf(Name) >= 0 then
680 Strs.Add(Format(' <img src="%s\%s" alt="%s,%d">',
681 [FImagePath, XMLEntity(Name), XMLEntity(Ghost), ID]));
685 Bmp := TBitmap.Create;
687 if Spps.TryGetImage(Ghost, ID, Bmp) then
689 Path := Options.ImageDir + PathDelim + Name;
690 Bmp.SaveToFile(Path);
691 Strs.Add(Format(' <img src="%s\%s" alt="%s,%d">',
692 [FImagePath, XMLEntity(Name), XMLEntity(Ghost), ID]));
694 FImageFiles.Add(Name); //
\8e\9f\89ñ
\82©
\82ç
\8cÄ
\82Ñ
\8fo
\82³
\82È
\82
\82Ä
\82¢
\82¢
\82æ
\82¤
\82É
\82·
\82é
696 Strs.Add(Format(' [%d]', [ID]));
703 procedure TBottleLogList.SaveToHTML(const FileName: String;
704 const Options: THTMLOutputOptions; SsParser: TSsParser);
708 ChannelAndGhost: String;
711 if ExtractFilePath(FileName) = ExtractFilePath(Options.ImageDir) then
712 FImagePath := ExtractFileName(Options.ImageDir)
714 FImagePath := Options.ImageDir;
716 Screen.Cursor := crHourGlass;
717 FImageFiles := TStringList.Create;
719 Strs := TStringList.Create;
723 Add('<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">');
725 Add('<style type="text/css"><!--');
726 Add('table.bottle td{font-family: monospace}');
727 if Options.UseColor = ucUse then
729 Add(Format('p.bottleattr {color: %s}', [ColorToHex(Pref.TalkColorH)]));
730 Add(Format('body {background-color: %s}', [ColorToHex(Pref.BgColor)]));
731 Add(Format('table.bottle tr.scope0 td.talk{color: %s}', [ColorToHex(Pref.TalkColorH)]));
732 Add(Format('table.bottle tr.scope1 td.talk{color: %s}', [ColorToHex(Pref.TalkColorU)]));
733 Add(Format('table.bottle tr.synchronized td.talk{color: %s}', [ColorToHex(Pref.TalkColorS)]));
734 Add('table.bottle td.surface {text-align: center}');
737 for i := 0 to Self.Count-1 do
739 if Assigned(FOnHTMLOutputWork) then
742 FOnHTMLOutputWork(Self, i, Cancel);
746 if Bottles[i].Ghost <> '' then
747 ChannelAndGhost := XMLEntity(Bottles[i].Channel) + '/' + XMLEntity(Bottles[i].Ghost)
749 ChannelAndGhost := XMLEntity(Bottles[i].Channel);
750 Add(Format('<p class="bottleattr">%s %s
\93\8a\95[%d
\93¯
\88Ó%d</p>', [
751 FormatDateTime('yyyy/mm/dd hh:nn:ss', Bottles[i].LogTime),
756 Add('<table class="bottle">');
757 PrintHTMLBottle(Strs, Bottles[i], SsParser, Options);
762 SaveToFile(FileName);
769 Screen.Cursor := crArrow;
773 procedure TBottleLogList.SaveToSstpLog(const FileName: String;
774 const WithChannel: boolean = false);
780 DayStr: array[1..7] of String = ('Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat');
784 Str := TStringList.Create;
785 for i := 0 to Self.Count - 1 do begin
786 Item := Self.Items[i] as TLogItem;
787 if Item.LogType = ltBottle then begin
788 Date := FormatDateTime('yyyy/mm/dd hh:nn:ss ', Item.LogTime);
789 Date := Date + '(' + DayStr[DayOfWeek(Item.LogTime)] + ')';
791 Date := Date + ',' + Item.Channel +',SEND,' + Item.Script
793 Date := Date + ',0.0.0.0,SEND,' + Item.Script;
797 Str.SaveToFile(FileName);
798 Self.SetLogModified(false); //
\82±
\82Ì
\83\8a\83X
\83g
\82Í
\95Û
\91¶
\82³
\82ê
\82½
804 procedure TBottleLogList.SaveToText(const FileName: String);
810 Str := TStringList.Create;
811 for i := 0 to Self.Count - 1 do
812 if (Self.Items[i] as TLogItem).LogType = ltBottle then
813 Str.Add((Self.Items[i] as TLogItem).Script);
814 Str.SaveToFile(FileName);
815 Self.SetLogModified(false); //
\82±
\82Ì
\83\8a\83X
\83g
\82Í
\95Û
\91¶
\82³
\82ê
\82½
821 procedure TBottleLogList.SaveToXMLFile(const FileName: String);
823 MessageNode, Child: TdomElement;
826 Parser: TXmlToDomParser;
827 Impl: TDomImplementation;
830 Impl := TDomImplementation.create(nil);
832 Parser := TXmlToDomParser.create(nil);
833 Parser.DOMImpl := Impl;
836 DOM := Parser.fileToDom(ExtractFilePath(Application.ExeName)+'xbtl.dat');
837 //
\82±
\82ê
\82Í
\96¾
\8e¦
\93I
\82ÉFree
\82µ
\82È
\82
\82Ä
\82æ
\82¢
840 documentElement.setAttribute('saved',
841 FormatDateTime('yy/mm/dd hh:nn:ss', Now));
842 documentElement.setAttribute('generator', VersionString);
843 documentElement.setAttribute('version', '1.0');
844 for i := 0 to Self.Count-1 do begin
845 Item := Self.GetBottles(i);
846 MessageNode := createElement('message');
847 MessageNode.setAttribute('mid', Item.MID);
848 documentElement.appendChild(MessageNode);
851 Child := createElement('date');
852 Child.appendChild(createTextNode(FormatDateTime('yy/mm/dd hh:nn:ss', Item.LogTime)));
853 MessageNode.appendChild(Child);
854 //
\83`
\83\83\83\93\83l
\83\8b
855 Child := createElement('channel');
856 Child.appendChild(createTextNode(Item.Channel));
857 MessageNode.appendChild(Child);
858 //
\83X
\83N
\83\8a\83v
\83g
859 Child := createElement('script');
860 Child.appendChild(createTextNode(Item.Script));
861 MessageNode.appendChild(Child);
863 Child := createElement('votes');
864 Child.appendChild(createTextNode(IntToStr(Item.Votes)));
865 MessageNode.appendChild(Child);
867 Child := createElement('agrees');
868 Child.appendChild(createTextNode(IntToStr(Item.Agrees)));
869 MessageNode.appendChild(Child);
871 Child := createElement('ghost');
872 Child.appendChild(createTextNode(Item.Ghost));
873 MessageNode.appendChild(Child);
877 FS := TFileStream.Create(FileName, fmCreate or fmShareExclusive);
879 DOM.writeCodeAsShiftJIS(FS);
883 Self.SetLogModified(false); //
\82±
\82Ì
\83\8a\83X
\83g
\82Í
\95Û
\91¶
\82³
\82ê
\82½
885 ShowMessage('xbtl.dat
\82ð
\8dÄ
\83C
\83\93\83X
\83g
\81[
\83\8b\82µ
\82Ä
\82
\82¾
\82³
\82¢
\81B');
888 Parser.DOMImpl.freeDocument(DOM);
896 procedure TBottleLogList.SetOnHTMLOutputWork(
897 const Value: TBottleLogHTMLOutputWork);
899 FOnHTMLOutputWork := Value;
902 procedure TBottleLogList.SetOnLoaded(const Value: TNotifyEvent);
907 procedure TBottleLogList.SetOnLoadFailure(
908 const Value: TBottleLogLoadFailureEvent);
910 FOnLoadFailure := Value;
913 procedure TBottleLogList.SetOnLoadWork(const Value: TNotifyEvent);
915 FOnLoadWork := Value;
918 procedure TBottleLogList.SetSelectedIndex(const Value: integer);
920 FSelectedIndex := Value;
923 procedure TBottleLogList.SetTitle(const Value: String);
928 procedure TBottleLogList.SortBottles(LogSortType: TBottleLogSortType);
930 if FOldSortColumn = LogSortType then
931 ASortDesc := not FOldSortDesc
935 ASortType := LogSortType;
936 Self.Sort(LogCompare);
937 FOldSortColumn := ASortType;
938 FOldSortDesc := ASortDesc;
941 procedure TBottleLogList.XMLLoaded(Sener: TObject);
943 Self.Assign(FXMLThread.List);
944 if Assigned(FOnLoaded) then FOnLoaded(Self);
948 procedure TBottleLogList.XMLLoadFailure(Sender: TObject;
949 const Message: String);
951 if Assigned(FOnLoadFailure) then
952 DoLoadFailure(Message);
957 constructor TLogXMLThread.Create(FileName: String);
959 inherited Create(true);
960 FList := TObjectList.Create(false); // OwnsObject = false (!!)
961 FFileName := FileName;
964 destructor TLogXMLThread.Destroy;
970 procedure TLogXMLThread.DoLoaded;
972 if Assigned(FOnLoaded) then
976 procedure TLogXMLThread.DoLoadFailure;
978 if Assigned(FOnLoadFailure) then
979 FOnLoadFailure(self, FLoadFailureMessage);
982 procedure TLogXMLThread.Execute;
983 var i, j, votes, agrees: integer;
985 ANode, Child: TdomElement;
988 Parser: TXmlToDomParser;
989 Impl: TDomImplementation;
990 Str, mid, channel, script, ghost: String;
993 Impl := TDomImplementation.create(nil);
995 Parser := TXmlToDomParser.create(nil);
996 Parser.DOMImpl := Impl;
999 DOM := Parser.fileToDom(FFileName); //
\82±
\82ê
\82Í
\96¾
\8e¦
\93I
\82ÉFree
\82µ
\82È
\82
\82Ä
\82æ
\82¢
1001 if not DOM.validate(nil, erReplace) then
1002 raise EXMLFileOpenException.Create('
\97L
\8cø
\82È
\83{
\83g
\83\8b\83\8d\83O
\8c`
\8e®
\82Å
\82Í
\82 \82è
\82Ü
\82¹
\82ñ
\81B');
1005 if DocumentElement = nil then
1007 FLoadFailureMessage := '
\97L
\8cø
\82È
\8c`
\8e®
\82Å
\82Í
\82 \82è
\82Ü
\82¹
\82ñ
\81B' +
1008 '
\83\8b\81[
\83g
\83^
\83O
\82ª
\82 \82è
\82Ü
\82¹
\82ñ';
1009 Synchronize(DoLoadFailure);
1012 if DocumentElement.nodeName <> 'bottlelog' then
1014 FLoadFailureMessage := '
\97L
\8cø
\82È
\8c`
\8e®
\82Å
\82Í
\82 \82è
\82Ü
\82¹
\82ñ
\81B' +
1015 'bottlelog
\82ª
\8c©
\82Â
\82©
\82è
\82Ü
\82¹
\82ñ';
1016 Synchronize(DoLoadFailure);
1019 Str := DocumentElement.getAttribute('version');
1020 if Str <> '1.0' then
1022 FLoadFailureMessage := Format('
\97L
\8cø
\82È
\8c`
\8e®
\82Å
\82Í
\82 \82è
\82Ü
\82¹
\82ñ
\81B' +
1023 '
\82±
\82Ì
\83\8d\83O
\83t
\83@
\83C
\83\8b\82Ì
\83o
\81[
\83W
\83\87\83\93(%s)
\82Í
\93Ç
\82Ý
\8d\9e\82ß
\82Ü
\82¹
\82ñ', [Str]);
1024 Synchronize(DoLoadFailure);
1027 for i := 0 to DocumentElement.childNodes.length-1 do
1029 if documentElement.childNodes.item(i).nodeType <> ntElement_Node then
1031 ANode := documentElement.childNodes.item(i) as TdomElement;
1032 if ANode.nodeName <> 'message' then
1034 mid := ANode.getAttribute('mid');
1041 for j := 0 to ANode.childNodes.length-1 do
1043 if ANode.childNodes.item(j).nodeType <> ntElement_Node then
1045 Child := ANode.childNodes.item(j) as TdomElement;
1046 if Child.nodeName = 'channel' then
1047 channel := Trim(Child.textContent)
1048 else if Child.nodeName = 'script' then
1049 script := Trim(Child.textContent)
1050 else if Child.nodeName = 'ghost' then
1051 ghost := Trim(Child.textContent)
1052 else if Child.nodeName = 'votes' then
1053 votes := StrToIntDef(Child.textContent, 0)
1054 else if Child.nodeName = 'agrees' then
1055 agrees := StrToIntDef(Child.textContent, 0)
1056 else if Child.nodeName = 'date' then
1057 TryStrToDateTime(Trim(Child.textContent), Time);
1059 Item := TLogItem.Create(ltBottle, mid, channel, script, ghost, time);
1060 Item.Votes := votes;
1061 Item.Agrees := agrees;
1062 Item.State := lsOpened;
1069 Synchronize(DoLoaded);
1072 on E: EParserException do
1074 FLoadFailureMessage := 'XML
\89ð
\90Í
\83G
\83\89\81[
\81B' + E.Message;
1075 Synchronize(DoLoadFailure);
1080 FLoadFailureMessage := 'XML
\83I
\81[
\83v
\83\93\8e\9e\82É
\83G
\83\89\81[
\82ª
\94
\90¶
\82µ
\82Ü
\82µ
\82½
\81B' +
1082 Synchronize(DoLoadFailure);
1087 Parser.DOMImpl.freeDocument(DOM);
1095 procedure TLogXMLThread.SetOnLoaded(const Value: TNotifyEvent);
1100 procedure TLogXMLThread.SetOnLoadFailure(const Value: TBottleLogLoadFailureEvent);
1102 FOnLoadFailure := Value;
1105 procedure TBottleLogList.SetLogModified(const Value: boolean);
1107 FLogModified := Value;