OSDN Git Service

First imported to cvs
[winbottle/winbottle.git] / bottleclient / LogForm.pas
1 unit LogForm;
2
3 interface
4
5 uses
6   Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
7   ComCtrls, ToolWin, StdCtrls, ExtCtrls, SsParser, BottleDef, Menus, FastSstp,
8   Clipbrd, Logs, ShellAPI;
9
10 type
11   TSaveLogType = (stLog, stLogWithChannels, stText, stXML);
12
13   TfrmLog = class(TForm)
14     ToolBar: TToolBar;
15     tbtnClear: TToolButton;
16     pnlUpper: TPanel;
17     SsParser: TSsParser;
18     StatusBar: TStatusBar;
19     tbtnSaveLog: TToolButton;
20     PopupMenuPreview: TPopupMenu;
21     mnPopCopy: TMenuItem;
22     tbtnVoteMessage: TToolButton;
23     PopupMenuListView: TPopupMenu;
24     mnPopUpVoteMessage: TMenuItem;
25     SaveDialog: TSaveDialog;
26     pnlPanel: TPanel;
27     lvwLog: TListView;
28     Splitter: TSplitter;
29     edtScript: TRichEdit;
30     mnPopUpCopyScript: TMenuItem;
31     PopupMenuSaveLog: TPopupMenu;
32     mnSaveLog: TMenuItem;
33     mnSaveLogChannel: TMenuItem;
34     mnSaveLogScript: TMenuItem;
35     mnSaveLogXML: TMenuItem;
36     ToolButton1: TToolButton;
37     mnJumpURL: TMenuItem;
38     mnPopUpAgreeMessage: TMenuItem;
39     tbtnAgreeMessage: TToolButton;
40     procedure tbtnClearClick(Sender: TObject);
41     procedure FormCreate(Sender: TObject);
42     procedure lvwLogChange(Sender: TObject; Item: TListItem;
43       Change: TItemChange);
44     procedure lvwLogDblClick(Sender: TObject);
45     procedure lvwLogKeyPress(Sender: TObject; var Key: Char);
46     procedure FormDestroy(Sender: TObject);
47     procedure lvwLogClick(Sender: TObject);
48     procedure mnSaveLogClick(Sender: TObject);
49     procedure lvwLogColumnClick(Sender: TObject; Column: TListColumn);
50     procedure mnPopUpCopyScriptClick(Sender: TObject);
51     procedure mnSaveLogChannelClick(Sender: TObject);
52     procedure mnSaveLogScriptClick(Sender: TObject);
53     procedure mnSaveLogXMLClick(Sender: TObject);
54     procedure lvwLogData(Sender: TObject; Item: TListItem);
55     procedure PopupMenuListViewPopup(Sender: TObject);
56   private
57     { Private \90é\8c¾ }
58     SortColumn: integer;  //\97ñ\83N\83\8a\83b\83N\83\\81[\83g\97p
59     SortDesc: boolean;    //\97ñ\83N\83\8a\83b\83N\83\\81[\83g\97p
60     procedure UpdateScriptColor(const Script: String);
61     procedure UpdateScriptNoColor(const Script: String);
62     procedure DoSaveLog(SaveType: TSaveLogType; Ext: String;
63       Filter: integer);
64     procedure mnURLClick(Sender: TObject);
65     procedure ExtractURLs(Script: String; Result: TStrings);
66   protected
67     procedure CreateParams(var Params: TCreateParams); override;
68   public
69     { Public \90é\8c¾ }
70     procedure AddScriptLog(const Script, Channel, MID, Ghost: String);
71     procedure AddSystemLog(const MessageString: String);
72     procedure SetBottleStatusToPlaying(const MID: String);
73     procedure SetBottleStatusToOpened(const MID: String);
74     procedure UpdateWindow;
75   end;
76
77
78 var
79   frmLog: TfrmLog;
80
81 const
82   IconBottle    = 17;
83   IconOpened    = 30;
84   IconPlaying   = 31;
85   IconSystemLog = 26;
86   SubChannel    = 0;
87   SubVotes      = 1;
88   SubAgrees     = 2;
89   SubScript     = 3;
90
91 implementation
92
93 uses MainForm;
94
95 {$R *.DFM}
96
97 { TfrmLog }
98
99 procedure TfrmLog.AddScriptLog(const Script, Channel, MID, Ghost: String);
100 var LogItem: TLogItem;
101     Sel: integer;
102 begin
103   if lvwLog.Selected <> nil then Sel := lvwLog.Selected.Index else Sel := -1;
104   LogItem := TLogItem.Create(ltBottle, MID, Channel, Script, Ghost, Now());
105   BottleLog.Insert(0, LogItem);
106   lvwLog.Items.Count := BottleLog.Count;
107   UpdateWindow;
108   if Sel >= 0 then begin
109     lvwLog.Selected := lvwLog.Items[Sel + 1];
110     lvwLog.Selected.Focused := true;
111   end;
112 end;
113
114 procedure TfrmLog.AddSystemLog(const MessageString: String);
115 var LogItem: TLogItem;
116     Sel: integer;
117 begin
118   if lvwLog.Selected <> nil then Sel := lvwLog.Selected.Index else Sel := -1;
119   LogItem := TLogItem.Create(ltSystemLog, '', '', MessageString, '', Now());
120   BottleLog.Insert(0, LogItem);
121   lvwLog.Items.Count := BottleLog.Count;
122   UpdateWindow;
123   if Sel >= 0 then begin
124     lvwLog.Selected := lvwLog.Items[Sel + 1];
125     lvwLog.Selected.Focused := true;
126   end;
127 end;
128
129 procedure TfrmLog.tbtnClearClick(Sender: TObject);
130 begin
131   BottleLog.Clear;
132   lvwLog.Items.Count := 0;
133   lvwLog.Invalidate;
134   lvwLogChange(Self, nil, ctState);
135 end;
136
137 procedure TfrmLog.FormCreate(Sender: TObject);
138 begin
139   SsParser.TagPattern.Assign(frmSender.SsParser.TagPattern);
140   SsParser.MetaPattern.Assign(frmSender.SsParser.MetaPattern);
141
142   with Pref.LogWindowPosition do begin
143     Self.Left   := Left;
144     Self.Top    := Top;
145     Self.Width  := Right - Left + 1;
146     Self.Height := Bottom - Top + 1;
147   end;
148   edtScript.Height := Pref.LogWindowDividerPos;
149 end;
150
151 procedure TfrmLog.FormDestroy(Sender: TObject);
152 begin
153   with Pref.LogWindowPosition do begin
154     Left   := Self.Left;
155     Top    := Self.Top;
156     Right  := Self.Left + Self.Width - 1;
157     Bottom := Self.Top + Self.Height - 1;
158   end;
159   Pref.LogWindowDividerPos := edtScript.Height;
160 end;
161
162 procedure TfrmLog.lvwLogChange(Sender: TObject; Item: TListItem;
163   Change: TItemChange);
164 var Script: String;
165     Log: TLogItem;
166 begin
167   StatusBar.Panels[0].Text := IntToStr(lvwLog.Items.Count) + '\8c\8f';
168   if Change = ctState then begin
169     Script := '';
170     if lvwLog.Selected <> nil then begin
171       Log := BottleLog.Bottles[Item.Index];
172       if Log.LogType = ltBottle then begin
173         Script := Log.Script;
174         frmSender.actVoteMessage.Enabled := true;
175         frmSender.actAgreeMessage.Enabled := true;
176         mnPopUpCopyScript.Enabled := true;
177       end else begin
178         frmSender.actVoteMessage.Enabled := false;
179         frmSender.actAgreeMessage.Enabled := false;
180         mnPopUpCopyScript.Enabled := false;
181       end
182     end else begin
183       frmSender.actVoteMessage.Enabled := false;
184       frmSender.actAgreeMessage.Enabled := false;
185       mnPopUpCopyScript.Enabled := false;
186     end;
187     frmSender.DoTrans(Script, [toConvertURL]);
188     if Pref.ColorScript then begin
189       UpdateScriptColor(Script);
190     end else begin
191       UpdateScriptNoColor(Script);
192     end;
193   end;
194   tbtnSaveLog.Enabled := lvwLog.Items.Count > 0;
195 end;
196
197 procedure TfrmLog.lvwLogDblClick(Sender: TObject);
198 var Script: String;
199     Opt: TScriptTransOptions;
200     SOpt: TSstpSendOptions;
201     Ghost: String;
202     Log: TLogItem;
203 begin
204   if lvwLog.Selected = nil then Exit;
205   //Log := TLogItem(lvwLog.Selected.Data);
206   Log := BottleLog.Bottles[lvwLog.Selected.Index];
207   if Log = nil then Exit;
208   if Log.LogType <> ltBottle then Exit;
209   Script := Log.Script;
210   Opt := [toConvertURL, toWaitScriptEnd];
211   if Pref.NoTransUrl then Opt := Opt + [toNoChoice];
212   if Pref.IgnoreFrequentYenS then Opt := Opt + [toIgnoreFrequentYenS];
213   frmSender.DoTrans(Script, Opt);
214
215   Ghost := frmSender.GetChannelPrefs(Log.Channel).TargetGhost;
216   if Ghost = '' then //\83`\83\83\83\93\83l\83\8b\8ew\92è\83S\81[\83X\83g
217     if frmSender.ChannelList.Channel[Log.Channel] <> nil then
218       Ghost := frmSender.ChannelList.Channel[Log.Channel].Ghost;
219   //\96Ú\95W\83S\81[\83X\83g\8c\88\92è
220   if Log.Ghost <> '' then Ghost := Log.Ghost;
221   if frmSender.GetChannelPrefs(Log.Channel).IgnoreIfGhost then
222     Ghost := frmSender.GetChannelPrefs(Log.Channel).TargetGhost;
223   //\83^\81[\83Q\83b\83g\83S\81[\83X\83g\8am\92è
224   Ghost := frmSender.SetHWndToFavoriteGhost(Ghost);
225   frmSender.FastSstp.SstpSender := 'SSTP Bottle -\81y\83\8d\83O\8dÄ\90\81z';
226   if Pref.NoTranslate then SOpt := [soNoTranslate] else SOpt := [];
227   frmSender.FastSstp.SstpSEND(Script, SOpt, frmSender.GhostNameToSetName(Ghost));
228 end;
229
230 procedure TfrmLog.UpdateScriptColor(const Script: String);
231 var i: integer;
232     UnyuTalking, Talked: boolean;
233 begin
234   SsParser.LeaveEscape := false;
235   SsParser.InputString := Script;
236   SsParser.LeaveEscape := true;
237   UnyuTalking := false;
238   Talked := false; //'\h\u\h\u'\82Ì\82æ\82¤\82È\83X\83N\83\8a\83v\83g\82Å\8bó\82«\8ds\82ð\8dì\82ç\82È\82¢\82½\82ß\82Ì\91[\92u
239   edtScript.Text := '';
240   edtScript.Color := Pref.BgColor;
241   for i := 0 to SsParser.Count-1 do begin
242     if (SsParser[i] = '\u') and not UnyuTalking then begin
243       UnyuTalking := true;
244       if Talked then begin
245         edtScript.SelText := #13#10;
246         Talked := false;
247       end;
248     end;
249     if (SsParser[i] = '\h') and UnyuTalking then begin
250       UnyuTalking := false;
251       if Talked then begin
252         edtScript.SelText := #13#10;
253         Talked := false;
254       end;
255     end;
256     if SsParser.MarkUpType[i] = mtStr then begin
257       if UnyuTalking then
258         edtScript.SelAttributes.Color := Pref.TalkColorU
259       else
260         edtScript.SelAttributes.Color := Pref.TalkColorH;
261       edtScript.SelText := SsParser[i];
262       Talked := true;
263     end;
264     if SsParser.MarkUpType[i] = mtMeta then begin
265       edtScript.SelAttributes.Color := Pref.MetaWordColor;
266       edtScript.SelText := SsParser[i];
267       Talked := true;
268     end;
269   end;
270 end;
271
272 procedure TfrmLog.UpdateScriptNoColor(const Script: String);
273 var Scr: String;
274     i: integer;
275     UnyuTalking, Talked, LastUnyuTalked: boolean;
276 begin
277   SsParser.LeaveEscape := false;
278   SsParser.InputString := Script;
279   SsParser.LeaveEscape := true;
280   edtScript.Text := '';
281   edtScript.Color := clWindow;
282   edtScript.DefAttributes.Color := clWindowText;
283   edtScript.SelAttributes.Color := clWindowText;
284   Talked := false;
285   UnyuTalking := false;
286   LastUnyuTalked := false;
287   for i := 0 to SsParser.Count-1 do begin
288     if (SsParser[i] = '\u') and not UnyuTalking then begin
289       UnyuTalking := true;
290     end;
291     if (SsParser[i] = '\h') and UnyuTalking then begin
292       UnyuTalking := false;
293     end;
294     if SsParser.MarkUpType[i] in [mtStr, mtMeta] then begin
295       if not Talked then begin
296         if UnyuTalking then Scr := '\82¤:' else Scr := '\82³:';
297       end;
298       if Talked and (UnyuTalking <> LastUnyuTalked) then begin
299         Scr := Scr + #13#10;
300         if UnyuTalking then Scr := Scr + '\82¤:' else Scr := Scr + '\82³:';
301       end;
302       Scr := Scr + SsParser[i];
303       Talked := true;
304       LastUnyuTalked := UnyuTalking;
305     end;
306   end;
307   edtScript.Text := Scr;
308 end;
309
310 procedure TfrmLog.lvwLogKeyPress(Sender: TObject; var Key: Char);
311 begin
312   if Key = #13 then lvwLogDblClick(Sender);
313 end;
314
315 procedure TfrmLog.CreateParams(var Params: TCreateParams);
316 begin
317   inherited;
318   Params.ExStyle := Params.ExStyle or WS_EX_APPWINDOW;
319 end;
320
321 procedure TfrmLog.lvwLogClick(Sender: TObject);
322 begin
323   with lvwLog do
324     Selected := Selected;
325 end;
326
327 procedure TfrmLog.mnSaveLogClick(Sender: TObject);
328 begin
329   DoSaveLog(stLog, 'log', 1);
330 end;
331
332 procedure TfrmLog.lvwLogColumnClick(Sender: TObject; Column: TListColumn);
333 var SortType: TBottleLogSortType;
334 begin
335   if SortColumn = Column.Index then
336     SortDesc := not SortDesc
337   else begin
338     SortColumn := Column.Index;
339     SortDesc := false;
340   end;
341   case SortColumn-1 of
342     -1: SortType := stLogTime;
343     subChannel: SortType := stChannel;
344     subVotes:   SortType := stVote;
345     subAgrees:  SortType := stAgree;
346     subScript:  SortType := stScript;
347   else SortType := stLogTime;
348   end;
349   BottleLog.SortBottles(SortType, SortDesc);
350   lvwLog.Invalidate;
351 end;
352
353
354 procedure TfrmLog.mnPopUpCopyScriptClick(Sender: TObject);
355 var
356   Log: TLogItem;
357   Clip: TClipBoard;
358 begin
359   Log := BottleLog.Bottles[frmLog.lvwLog.Selected.Index];
360   if Log = nil then Exit;
361   Clip := ClipBoard();
362   Clip.SetTextBuf(PChar(Log.Script));
363 end;
364
365 procedure TfrmLog.SetBottleStatusToOpened(const MID: String);
366 begin
367   if BottleLog.Bottle(MID) <> nil then begin
368     BottleLog.Bottle(MID).State := lsOpened;
369     lvwLog.Invalidate;
370   end;
371 end;
372
373 procedure TfrmLog.SetBottleStatusToPlaying(const MID: String);
374 begin
375   if BottleLog.Bottle(MID) <> nil then begin
376     BottleLog.Bottle(MID).State := lsPlaying;
377     lvwLog.Invalidate;
378   end;
379 end;
380
381 procedure TfrmLog.DoSaveLog(SaveType: TSaveLogType; Ext: String; Filter: integer);
382 var i: integer;
383     Log: TStringList;
384     LogItem: TLogItem;
385     Date: String;
386     TmpScript: String;
387 const
388   DayStr: array[1..7] of String = ('Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat');
389 begin
390   SaveDialog.InitialDir := ExtractFileDir(Application.ExeName);
391   SaveDialog.DefaultExt := Ext;
392   SaveDialog.FilterIndex := Filter;
393   if SaveDialog.Execute then begin
394     Log := nil;
395     try
396       Log := TStringList.Create;
397       case SaveType of
398         stLog, stLogWithChannels: begin
399           for i := 0 to BottleLog.Count -1 do begin
400             LogItem := BottleLog.Bottles[i];
401             if LogItem = nil then Continue;
402             if LogItem.LogType <> ltBottle then Continue;
403             Date := FormatDateTime('yyyy/mm/dd hh:nn:ss ', LogItem.LogTime);
404             Date := Date + '(' + DayStr[DayOfWeek(LogItem.LogTime)] + ')';
405             if SaveType = stLogWithChannels then
406               Date := Date + ',' + LogItem.Channel +',SEND,' + LogItem.Script
407             else
408               Date := Date + ',0.0.0.0,SEND,' + LogItem.Script;
409             Log.Add(Date);
410           end;
411         end;
412         stText: begin
413           for i := 0 to BottleLog.Count -1 do begin
414             LogItem := BottleLog.Bottles[i];
415             if LogItem = nil then Continue;
416             if LogItem.LogType <> ltBottle then Continue;
417             Log.Add(LogItem.Script);
418           end;
419         end;
420         stXML: begin
421           Log.Add('<?xml version=''1.0'' encoding=''Shift_JIS''?>');
422           Log.Add('<bottlelog>');
423           for i := 0 to BottleLog.Count -1 do begin
424             LogItem := BottleLog.Bottles[i];
425             if LogItem = nil then Continue;
426             if LogItem.LogType <> ltBottle then Continue;
427             Date := FormatDateTime('yyyy/mm/dd hh:nn:ss', LogItem.LogTime);
428             Log.Add(Format('<message mid=''%s''>', [LogItem.MID]));
429             Log.Add('<date>' + Date + '</date>');
430             Log.Add('<channel>' + LogItem.Channel + '</channel>');
431             //
432             TmpScript := LogItem.Script;
433             TmpScript := StringReplace(TmpScript, '<', '&lt;', [rfReplaceAll]);
434             TmpScript := StringReplace(TmpScript, '>', '&gt;', [rfReplaceAll]);
435             Log.Add('<script>' + TmpScript + '</script>');
436             //
437             if LogItem.Ghost = '' then
438               Log.Add('<ghost />')
439             else begin
440               TmpScript := LogItem.Ghost;
441               TmpScript := StringReplace(TmpScript, '<', '&lt;', [rfReplaceAll]);
442               TmpScript := StringReplace(TmpScript, '>', '&gt;', [rfReplaceAll]);
443               Log.Add(Format('<ghost>%s</ghost>', [TmpScript]));
444             end;
445             Log.Add('</message>');
446           end;
447           Log.Add('</bottlelog>');
448         end;
449       end;
450       Log.SaveToFile(SaveDialog.FileName);
451     finally
452       Log.Free;
453     end;
454   end;
455 end;
456
457 procedure TfrmLog.mnSaveLogChannelClick(Sender: TObject);
458 begin
459   DoSaveLog(stLogWithChannels, 'log', 1);
460 end;
461
462 procedure TfrmLog.mnSaveLogScriptClick(Sender: TObject);
463 begin
464   DoSaveLog(stText, 'txt', 2);
465 end;
466
467 procedure TfrmLog.mnSaveLogXMLClick(Sender: TObject);
468 begin
469   DoSaveLog(stXML, 'xml', 3);
470 end;
471
472 procedure TfrmLog.lvwLogData(Sender: TObject; Item: TListItem);
473 var i: integer;
474     Log: TLogItem;
475 begin
476   i := Item.Index;
477   Log := BottleLog.Bottles[i];
478   with Item do begin
479     Caption := FormatDateTime('yy/mm/dd hh:nn:ss', Log.LogTime);
480     SubItems.Clear;
481     if Log.Ghost <> '' then
482       SubItems.Add(Log.Channel + '/' + Log.Ghost)
483     else
484       SubItems.Add(Log.Channel);
485     SubItems.Add(IntToStr(Log.Votes));
486     SubItems.Add(IntToStr(Log.Agrees));
487     SubItems.Add(Log.Script);
488
489     if Log.LogType = ltBottle then begin
490       case Log.State of
491         lsUnopened: ImageIndex := IconBottle;
492         lsPlaying:  ImageIndex := IconPlaying;
493         lsOpened:   ImageIndex := IconOpened;
494       end;
495     end else
496       ImageIndex := IconSystemLog;
497   end;
498 end;
499
500 procedure TfrmLog.UpdateWindow;
501 begin
502   lvwLog.Items.Count := BottleLog.Count;
503   lvwLog.Invalidate;
504   lvwLogChange(Self, lvwLog.Selected, ctState);
505 end;
506
507 procedure TfrmLog.PopupMenuListViewPopup(Sender: TObject);
508 var Log: TLogItem;
509     Child: TMenuItem;
510     Urls: TStringList;
511     i: integer;
512 begin
513   for i := 0 to mnJumpURL.Count-1 do begin
514     mnJumpURL.Items[i].Free;
515   end;
516   mnJumpURL.Enabled := false;
517   if lvwLog.Selected = nil then Exit;
518   Log := BottleLog.Bottles[lvwLog.Selected.Index];
519   if Log = nil then Exit;
520   Urls := nil;
521   try
522     Urls := TStringList.Create;
523     ExtractURLs(Log.Script, Urls);
524     for i := 0 to Urls.Count-1 do begin
525       Child := TMenuItem.Create(Self);
526       with Child do begin
527         Caption := Format('(&%d) %s', [i+1, Urls[i]]);
528         OnClick := mnURLClick;
529         AutoHotkeys := maManual;
530         mnJumpURL.Add(Child);
531       end;
532     end;
533     mnJumpURL.Enabled := Urls.Count > 0;
534   finally
535     Urls.Free;
536   end;
537 end;
538
539 procedure TfrmLog.mnURLClick(Sender: TObject);
540 var URL: String;
541 begin
542   URL := (Sender as TMenuItem).Caption;
543   RegExp.Subst('s/^\(&?\d\) //', URL);
544   ShellExecute(Handle, 'open', PChar(URL), nil, nil, SW_SHOW);
545 end;
546
547 procedure TfrmLog.ExtractURLs(Script: String; Result: TStrings);
548 var i, u, j: integer;
549     s: String;
550 begin
551   Result.Clear;
552   SsParser.LeaveEscape := false;
553   SsParser.InputString := Script;
554   SsParser.LeaveEscape := true;
555   for i := 0 to SsParser.Count-1 do begin
556     if (SsParser.Match(SsParser[i], '\URL%b') > 0) then begin
557       for u := 7 downto 1 do begin
558         if (SsParser.Match(SsParser[i],
559             '\URL%b'+StringReplace(StringOfChar('-', u*2),
560             '-', '%b', [rfReplaceAll]))) > 0 then begin
561           for j := 1 to u do begin
562             s := SsParser.GetParam(SsParser[i], j*2);
563             if Pos('http://', s) > 0 then Result.Add(s);
564           end;
565           Break;
566         end;
567       end;
568       if SsParser.Match(SsParser[i], '\URL%b%b') = 0 then begin //\8aÈ\88Õ\94ÅURL\95Ï\8a·
569         //\8aÈ\88Õ\8c`\8e®\URL\83^\83O\95Ï\8a·
570         s := SsParser.GetParam(SsParser[i], 1);
571         if Pos('http://', s) > 0 then Result.Add(s);
572       end;
573     end;
574   end;
575 end;
576
577 end.