OSDN Git Service

最新100レス表示の表示数を拡張できるようにオプションを追加
[gikonavigoeson/gikonavi.git] / Favorite.pas
1 unit Favorite;
2
3 interface
4
5 uses
6         Messages, SysUtils, Classes, Contnrs, ComCtrls, {HttpApp,} YofUtils,
7         GikoSystem{, XMLIntf, XMLDoc}, GikoXMLDoc, BoardGroup, windows;
8         {SAX, SAXHelpers, SAXComps, SAXKW;}
9
10 type
11         TFavoriteFolder = class
12         end;
13
14         TFavoriteItem = class(TObject)
15         private
16                 FURL                            : string;
17                 FTitle                  : string;
18         public
19                 function GetItemTitle : string; virtual;abstract;
20                 property URL                            : string        read FURL write FURL;   // Item \82ª\8eæ\93¾\82Å\82«\82È\82­\82Ä\82à URL \82Í\8fí\82É\95Û\8e\9d\82³\82ê\82é
21                 property Title                  : string        read FTitle write FTitle;
22         end;
23         TFavoriteBoardItem = class(TFavoriteItem)
24         private
25                 FItem                           : TBoard;
26                 function        GetItem : TBoard;
27         public
28                 constructor Create( inURL : string; inTitle : string = ''; inItem : TBoard = nil );
29                 constructor CreateWithItem( inItem : TBoard );
30                 destructor Destory;
31                 function GetItemTitle : string; override;
32                 property Item                           : TBoard        read GetItem write FItem;
33         end;
34
35         TFavoriteThreadItem = class(TFavoriteItem)
36         private
37                 FItem                           : TThreadItem;
38                 function        GetItem : TThreadItem;
39         public
40                 constructor Create( inURL : string; inTitle : string = ''; inItem : TThreadItem = nil );
41                 constructor CreateWithItem( inItem : TThreadItem );
42                 destructor Destory;
43                 function GetItemTitle : string; override;
44                 property Item                           : TThreadItem   read GetItem write FItem;
45         end;
46
47         TFavoriteDM = class(TDataModule)
48         private
49                 { Private \90é\8c¾ }
50         FAbEnd: Boolean;
51                 FTreeView: TTreeView;
52                 FModified: boolean;
53                 procedure ReadNode(Node: IXMLNode; Stack: TStack; TreeView: TTreeView);
54                 procedure AddSaveString(Node: TTreeNode; SaveList: TStringList);
55         public
56                 { Public \90é\8c¾ }
57                 procedure Clear;
58                 function GetFavoriteFilePath() : String;
59                 function SaveFavoriteFile(FileName: String) : Boolean;
60                 procedure SetFavTreeView(TreeView: TTreeView);
61                 procedure ReadFavorite;
62                 procedure WriteFavorite;
63                 procedure URLReplace(oldURLs: TStringList; newURLs: TStringList);
64                 property TreeView: TTreeView read FTreeView;
65                 property Modified: boolean read FModified write FModified;
66         property AbEnd: Boolean read FAbEnd write FAbEnd;
67         end;
68
69 var
70         FavoriteDM: TFavoriteDM;
71 const
72         FAVORITE_LINK_NAME = '\83\8a\83\93\83N';
73
74 implementation
75
76 uses    ExternalBoardManager, ExternalBoardPlugInMain,  MojuUtils;
77
78 const
79         FAVORITE_ROOT_NAME = '\82¨\8bC\82É\93ü\82è';
80         FAVORITE_FILE_NAME = 'Favorite.xml';
81
82 {$R *.dfm}
83
84 constructor TFavoriteBoardItem.Create(
85         inURL           : string;
86         inTitle : string = '';
87         inItem  : TBoard = nil
88 );
89 begin
90
91         inherited Create;
92
93         URL             := inURL;
94         Title   := inTitle;
95         Item    := inItem;
96
97 end;
98
99 constructor TFavoriteBoardItem.CreateWithItem(
100         inItem  : TBoard
101 );
102 begin
103
104         Create( inItem.URL, inItem.Title, inItem );
105
106 end;
107 destructor TFavoriteBoardItem.Destory;
108 begin
109         if FItem <> nil then
110                 FItem.Free;
111         inherited;
112 end;
113 //! \95Û\8e\9d\82µ\82Ä\82¢\82é\94Â\82Ì\83^\83C\83g\83\8b\82ð\95Ô\82·
114 function TFavoriteBoardItem.GetItemTitle : string;
115 begin
116         Result := '';
117         //\88ê\93x\82à\94Â\82ð\8aJ\82¢\82Ä\82¢\82È\82¢\82Æ\82«\81i\8bN\93®\8e\9e\82É\83L\83\83\83r\83l\83b\83g\82ð\82¨\8bC\82É\93ü\82è\82Æ\82©\81j
118         //\82Ì\82Æ\82«\82ÉFItem\82ªnil\82È\82Ì\82Å\82»\82Ì\82Æ\82«\82Í\82×\82Á\82Æ\8c\9f\8dõ
119         if FItem = nil then begin
120                 FItem := BBSsFindBoardFromURL(URL);
121         end;
122         if FItem <> nil then begin
123                 try
124                         if not FItem.IsThreadDatRead then begin
125                                 GikoSys.ReadSubjectFile(FItem);
126                         end;
127                 except
128                 end;
129                 Result := FItem.Title;
130         end;
131 end;
132 function        TFavoriteBoardItem.GetItem : TBoard;
133 var
134         protocol, host, path, document, port, bookmark : string;
135         BBSID   : string;
136         tmpURL  : string;
137 begin
138
139         if FItem = nil then begin
140                 FItem := BBSsFindBoardFromURL( URL );
141                 if FItem = nil then begin
142                         tmpURL := URL;
143                         GikoSys.ParseURI( tmpURL, protocol, host, path, document, port, bookmark );
144                         if GikoSys.Is2chHost( host ) then begin
145                                 BBSID := GikoSys.URLToID( tmpURL );
146                                 FItem := BBSs[ 0 ].FindBBSID( BBSID );
147                                 if FItem <> nil then
148                                         URL := FItem.URL;
149                         end;
150                         {
151                         // \81¦\8dì\82Á\82Ä\82à\81A\92Ç\89Á\82·\82é\83J\83e\83S\83\8a\82ª\96³\82¢\82Ì\82Å\8c\83\82µ\82­\95Û\97¯
152                         FItem                           := GikoSys.GetUnknownBoard( nil, URL );
153                         FItem.Title     := Title;
154                         }
155                 end;
156         end;
157
158         Result := FItem;
159
160 end;
161
162 constructor TFavoriteThreadItem.Create(
163         inURL           : string;
164         inTitle : string = '';
165         inItem  : TThreadItem = nil
166 );
167 begin
168
169         inherited Create;
170         URL             := inURL;
171
172         Title   := inTitle;
173         Item    := inItem;
174
175 end;
176
177 constructor TFavoriteThreadItem.CreateWithItem(
178         inItem  : TThreadItem
179 );
180 begin
181
182         Create( inItem.URL, inItem.Title, inItem );
183
184 end;
185 destructor TFavoriteThreadItem.Destory;
186 begin
187         if FItem <> nil then
188         FItem.Free;
189     inherited;
190 end;
191 //! \95Û\8e\9d\82µ\82Ä\82¢\82é\83X\83\8c\82Ì\83^\83C\83g\83\8b\82ð\95Ô\82·
192 function TFavoriteThreadItem.GetItemTitle : string;
193 begin
194         Result := '';
195         if FItem = nil then begin
196                 FItem := BBSsFindThreadFromURL(URL);
197         end;
198         if FItem <> nil then begin
199                 Result := FItem.Title;
200         end;
201 end;
202
203 function        TFavoriteThreadItem.GetItem : TThreadItem;
204 var
205         board                                   : TBoard;
206         boardURL                        : string;
207         browsableURL    : string;
208         protocol, host, path, document, port, bookmark : string;
209         BBSID, BBSKey   : string;
210         tmpURL                          : string;
211 begin
212
213         Result := nil;
214         if FItem = nil then begin
215                 browsableURL    := GikoSys.GetBrowsableThreadURL( URL );
216                 boardURL                        := GikoSys.GetThreadURL2BoardURL( browsableURL );
217                 board                                   := BBSsFindBoardFromURL( boardURL );
218
219                 if board = nil then begin
220                         tmpURL := URL;
221                         GikoSys.ParseURI( tmpURL, protocol, host, path, document, port, bookmark );
222                         if GikoSys.Is2chHost( host ) then begin
223                                 GikoSys.Parse2chURL( tmpURL, path, document, BBSID, BBSKey );
224                                 board := BBSs[ 0 ].FindBBSID( BBSID );
225                         end;
226
227                         if board = nil then begin
228                                 Exit;
229                                 // \81¦\8dì\82Á\82Ä\82à\81A\92Ç\89Á\82·\82é\83J\83e\83S\83\8a\82ª\96³\82¢\82Ì\82Å\8c\83\82µ\82­\95Û\97¯
230                                 //board := GikoSys.GetUnknownBoard( nil, boardURL )
231                         end;
232                 end;
233
234                 FItem := board.FindThreadFromURL( browsableURL );
235
236                 if FItem = nil then begin
237                         tmpURL := URL;
238                         GikoSys.ParseURI( tmpURL, protocol, host, path, document, port, bookmark );
239                         if GikoSys.Is2chHost( host ) then begin
240                                 GikoSys.Parse2chURL( tmpURL, path, document, BBSID, BBSKey );
241                                 FItem := BBSs[ 0 ].FindThreadItem( BBSID, BBSKey + '.dat' );
242                                 if FItem <> nil then
243                                         URL := FItem.URL;
244                         end;
245                 end;
246
247                 if FItem = nil then begin
248                         FItem := TThreadItem.Create( board.BoardPlugIn, board, browsableURL );
249
250                         FItem.Title := Title;
251                         board.Add( FItem );
252                 end;
253         end;
254
255         Result := FItem;
256
257 end;
258
259 procedure TFavoriteDM.Clear;
260 var
261         Node    : TTreeNode;
262 begin
263         TreeView.Items.BeginUpdate;
264         Node    := TreeView.Items.GetFirstNode;
265         while Node <> nil do begin
266                 if TObject(Node.Data) <> nil then
267                                 TObject(Node.Data).Free;
268                 Node := Node.GetNext;
269         end;
270                 TreeView.Items.Clear;
271                 TreeView.Items.EndUpdate;
272
273     FavoriteDM.Modified := true;
274 end;
275
276 procedure TFavoriteDM.SetFavTreeView(TreeView: TTreeView);
277 begin
278         FTreeView := TreeView;
279 end;
280
281 procedure TFavoriteDM.ReadFavorite;
282 var
283         FileName: string;
284         XMLDoc: IXMLDocument;
285         XMLNode: IXMLNode;
286         Node: TTreeNode;
287         i: Integer;
288         FavFolder: TFavoriteFolder;
289         LinkExists: Boolean;
290     Stack: TStack;
291 begin
292     FABend := False;
293     
294         FavoriteDM.Modified := true;
295         FileName := GikoSys.GetConfigDir + FAVORITE_FILE_NAME;
296
297         FavFolder := TFavoriteFolder.Create;
298         Node := FTreeView.Items.AddChildObjectFirst(nil, FAVORITE_ROOT_NAME, FavFolder);
299         Node.ImageIndex := 14;
300         Node.SelectedIndex := 14;
301
302         if FileExists(FileName) then begin
303                 try
304             XMLDoc := IXMLDocument.Create;
305                         //XMLDoc := LoadXMLDocument(FileName);
306             LoadXMLDocument(FileName, XMLDoc);
307                         XMLNode := XMLDoc.DocumentElement;
308
309                         Stack := TStack.Create;
310                         try
311                                 Stack.Push(Node);
312                                 LinkExists := False;
313                                 if XMLNode.NodeName = 'favorite' then begin
314                                         for i := XMLNode.ChildNodes.Count - 1 downto 0 do begin
315                                                 ReadNode(XMLNode.ChildNodes[i], Stack, FTreeView);
316                                                 if (XMLNode.ChildNodes[i].NodeName = 'folder') and
317                                                          (XMLNode.ChildNodes[i].Attributes['title'] = FAVORITE_LINK_NAME) then begin
318                                                         LinkExists := True;
319                                                 end;
320                                         end;
321                                 end;
322                                 if not LinkExists then begin
323                                         FavFolder := TFavoriteFolder.Create;
324                                         Node := FTreeView.Items.AddChildObjectFirst(Node, FAVORITE_LINK_NAME, FavFolder);
325                                         Node.ImageIndex := 14;
326                                         Node.SelectedIndex := 14;
327                                 end;
328
329                         finally
330                                 Stack.Free;
331                 XMLDoc.Free;
332                         end;
333                 except
334             on e : Exception do begin
335                 FABend := True;
336             end;
337                 end;
338         end;
339
340 end;
341
342 procedure TFavoriteDM.ReadNode(Node: IXMLNode; Stack: TStack; TreeView: TTreeView);
343 var
344         i: Integer;
345
346         ParentNode: TTreeNode;
347         CurrentNode: TTreeNode;
348         FavFolder: TFavoriteFolder;
349         FavBoard: TFavoriteBoardItem;
350         FavThread: TFavoriteThreadItem;
351         board                           : TBoard;
352         threadItem      : TThreadItem;
353 begin
354         if Node.NodeName = 'folder' then begin
355         CurrentNode := nil;
356                 ParentNode := Stack.Peek;
357                 if TObject(ParentNode.Data) is TFavoriteFolder then begin
358                         FavFolder := TFavoriteFolder.Create;
359                         CurrentNode := TreeView.Items.AddChildObjectFirst(ParentNode, Node.Attributes['title'], FavFolder);
360                         CurrentNode.ImageIndex := 14;
361                         CurrentNode.SelectedIndex := 14;
362                         Stack.Push(CurrentNode);
363                 end;
364                 for i := Node.ChildNodes.Count - 1 downto 0 do begin
365                         ReadNode(Node.ChildNodes[i], Stack, TreeView);
366                 end;
367                 if CurrentNode <> nil then
368                         CurrentNode.Expanded := Node.Attributes[ 'expanded' ] = 'true';
369                 if Stack.Count <> 0 then
370                         Stack.Pop;
371         end else if Node.NodeName = 'favitem' then begin
372                 try
373                         ParentNode := Stack.Peek;
374                         if TObject(ParentNode.Data) is TFavoriteFolder then begin
375                                 if Node.Attributes['favtype'] = 'board' then begin
376                                         FavBoard := nil;
377                                         // \8b\8c\8e®\82Ì\82¨\8bC\82É\93ü\82è\82Æ\82Ì\8cÝ\8a·\90«\82Ì\82½\82ß
378                                         if Length( Node.Attributes[ 'bbs' ] ) > 0 then begin
379                                                 board := BBSsFindBoardFromBBSID( Node.Attributes[ 'bbs' ] );
380                                                 if board <> nil then
381                                                         FavBoard := TFavoriteBoardItem.Create(
382                                                                 board.URL, MojuUtils.UnSanitize(Node.Attributes[ 'title' ]), board );
383                                         end else begin
384                                                 FavBoard := TFavoriteBoardItem.Create(
385                                                         Node.Attributes[ 'url' ], MojuUtils.UnSanitize(Node.Attributes[ 'title' ]), nil );
386                                         end;
387                                         CurrentNode := TreeView.Items.AddChildObjectFirst(ParentNode, UnSanitize(Node.Attributes['title']), FavBoard);
388                                         CurrentNode.ImageIndex := 15;
389                                         CurrentNode.SelectedIndex := 15;
390                                 end else if Node.Attributes['favtype'] = 'thread' then begin
391                                         // \8b\8c\8e®\82Ì\82¨\8bC\82É\93ü\82è\82Æ\82Ì\8cÝ\8a·\90«\82Ì\82½\82ß
392                                         if Length( Node.Attributes[ 'bbs' ] ) > 0 then begin
393                                                 board := BBSsFindBoardFromBBSID( Node.Attributes[ 'bbs' ] );
394                                                 if board = nil then
395                                                         Exit;
396
397                                                 if not board.IsThreadDatRead then
398                                                         GikoSys.ReadSubjectFile( board );
399                                                 threadItem := board.FindThreadFromFileName( Node.Attributes[ 'thread' ] );
400                                                 if threadItem = nil then begin
401                                                         threadItem := TThreadItem.Create(
402                                                                 board.BoardPlugIn,
403                                 board,
404                                                                 GikoSys.Get2chBoard2ThreadURL( board, ChangeFileExt( Node.Attributes[ 'thread' ], '' ) ) );
405                                                         threadItem.Title := UnSanitize(Node.Attributes[ 'title' ]);
406                                                         board.Add( threadItem );
407                                                 end;
408                                                 FavThread := TFavoriteThreadItem.Create(
409                                                         threadItem.URL, UnSanitize(Node.Attributes[ 'title' ]), threadItem );
410                         threadItem.Free;
411                                         end else begin
412                                                 FavThread := TFavoriteThreadItem.Create(
413                                                         Node.Attributes[ 'url' ], UnSanitize(Node.Attributes[ 'title' ]), nil );
414                                         end;
415                                         CurrentNode := TreeView.Items.AddChildObjectFirst(ParentNode, UnSanitize(Node.Attributes['title']), FavThread);
416                                         CurrentNode.ImageIndex := 16;
417                                         CurrentNode.SelectedIndex := 16;
418                                 end;
419                         end;
420                 except
421                         // \82±\82Ì\83A\83C\83e\83\80\82Å\96â\91è\82ª\8bN\82«\82Ä\82à\91¼\82Ì\83A\83C\83e\83\80\82É\89e\8b¿\82ð\97^\82¦\82½\82­\82È\82¢\82Ì\82Å
422                 end;
423         end;
424 end;
425
426 procedure TFavoriteDM.WriteFavorite;
427 var
428         FileName, tmpFileName: string;
429         SaveList: TStringList;
430
431 begin
432     FavoriteDM.Modified := true;
433         FileName := GikoSys.GetConfigDir + FAVORITE_FILE_NAME;
434         if FileExists(FileName) then begin
435                 tmpFileName := GikoSys.GetConfigDir + '~' + FAVORITE_FILE_NAME;
436                 if FileExists(tmpFileName) then
437                         SysUtils.DeleteFile(tmpFileName); //SysUtils.\82ð\82Â\82¯\82È\82¢\82ÆWinAPI\82Æ\8bæ\95Ê\82Å\82«\82È\82¢\82Ì\82Å
438                 RenameFile(FileName, tmpFileName);
439         end;
440         SaveList := TStringList.Create;
441         try
442                 SaveList.Add('<?xml version="1.0" encoding="Shift_JIS" standalone="yes"?>');
443                 SaveList.Add('<favorite>');
444                 try
445                         AddSaveString(TreeView.Items.GetFirstNode.getFirstChild, SaveList);
446                 except
447                 end;
448                 SaveList.Add('</favorite>');
449                 SaveList.SaveToFile(FileName);
450         finally
451                 SaveList.Free;
452         end;
453 end;
454
455 procedure TFavoriteDM.AddSaveString(Node: TTreeNode; SaveList: TStringList);
456 var
457         s: string;
458         FavBoard: TFavoriteBoardItem;
459         FavThread: TFavoriteThreadItem;
460         data : Pointer;
461 begin
462         while Node <> nil do begin
463                 data := Node.Data;
464                 if TObject(data) is TFavoriteFolder then begin
465                         if Node.Expanded then
466                                 s := Format('<folder title="%s" expanded="true">', [HtmlEncode(Node.Text)])
467                         else
468                                 s := Format('<folder title="%s" expanded="false">', [HtmlEncode(Node.Text)]);
469                         SaveList.Add(s);
470                         AddSaveString(Node.getFirstChild, SaveList);
471                         SaveList.Add('</folder>');
472                 end else if TObject(data) is TFavoriteBoardItem then begin
473                         FavBoard := TFavoriteBoardItem(data);
474                         s := Format('<favitem type="2ch" favtype="board" url="%s" title="%s"/>',
475                                                                         [HtmlEncode( FavBoard.URL ), HtmlEncode(MojuUtils.Sanitize(Node.Text))]);
476                         SaveList.Add(s);
477                 end else if TObject(data) is TFavoriteThreadItem then begin
478                         FavThread := TFavoriteThreadItem(data);
479                         s := Format('<favitem type="2ch" favtype="thread" url="%s" title="%s"/>',
480                                                                         [HtmlEncode( FavThread.URL ), HtmlEncode(MojuUtils.Sanitize(Node.Text))]);
481                         SaveList.Add(s);
482                 end;
483                 Node := Node.getNextSibling;
484         end;
485 end;
486
487 function TFavoriteDM.SaveFavoriteFile(FileName: String) : Boolean;
488 var
489         FavoriteFilePath: string;
490                 tempStringList: TStringList;
491 begin
492         WriteFavorite;
493         FavoriteFilePath := GikoSys.GetConfigDir + FAVORITE_FILE_NAME;
494
495         if FileExists( FavoriteFilePath ) then begin
496                 tempStringList := TStringList.Create;
497                 try
498                         tempStringList.LoadFromFile( FavoriteFilePath );
499                         tempStringList.SaveToFile( FileName );
500                 finally
501                         tempStringList.Free;
502                 end;
503                 Result := true;
504         end else begin
505                 Result := false;
506         end;
507 end;
508
509 procedure TFavoriteDM.URLReplace(oldURLs: TStringList; newURLs: TStringList);
510 var
511         i                                       : Integer;
512                 tmpURL: string;
513     oldHost: string;
514     oldBoardName: string;
515     newHost: string;
516     newBoardName: string;
517                 tempString: string;
518         favBoard        : TFavoriteBoardItem;
519         favThread       : TFavoriteThreadItem;
520         favorites       : TTreeNodes;
521         Node                    : TTreeNode;
522 begin
523
524         // \96Ê\93|\82¾\82¯\82Çthread\82Í\82»\82ê\82¼\82êURL\82ð\83`\83F\83b\83N\82µ\82È\82ª\82ç\82â\82Á\82Ä\82©\82È\82«\82á\82¢\82¯\82È\82¢\81B
525         favorites := FavoriteDM.FTreeView.Items;
526         for i := 0 to oldURLs.Count - 1 do begin
527                 try
528                         tmpURL                  := Copy(oldURLs[i], 1, Length(oldURLs[i]) -1);
529                         oldHost                 := Copy(tmpURL, 1, LastDelimiter('/', tmpURL) );
530                         oldBoardName    := Copy(tmpURL, LastDelimiter('/', tmpURL), Length(tmpURL) ) + '/';
531                         tmpURL                  := Copy(newURLs[i], 1, Length(newURLs[i]) -1);
532                         newHost                 := Copy(tmpURL, 1, LastDelimiter('/', tmpURL) );
533                         newBoardName    := Copy(tmpURL, LastDelimiter('/', tmpURL), Length(tmpURL) ) + '/';
534
535                         Node := favorites.GetFirstNode.getFirstChild;
536                         while Node <> nil do begin
537                                 try
538                                         if TObject( Node.Data ) is TFavoriteBoardItem then begin
539                                                 favBoard := TFavoriteBoardItem( Node.Data );
540                                                 if favBoard = nil then continue;
541                                                 tempString := favBoard.URL;
542                                                 if ( AnsiPos(oldBoardName, tempString) <> 0 ) and ( AnsiPos(oldHost, tempString ) <> 0 ) then begin
543                                                         tempString              := StringReplace(tempString, oldHost, newHost,[]);
544                                                         favBoard.URL    := tempString;
545                                                 end;
546                                         end else if TObject( Node.Data ) is TFavoriteThreadItem then begin
547                                                 favThread := TFavoriteThreadItem( Node.Data );
548                                                 if favThread = nil then continue;
549                                                 tempString := favThread.URL;
550                                                 if ( AnsiPos(oldBoardName, tempString) <> 0 ) and ( AnsiPos(oldHost, tempString ) <> 0 ) then begin
551                                                         tempString              := StringReplace(tempString, oldHost, newHost,[]);
552                                                         favThread.URL   := tempString;
553                                                 end;
554                                         end;
555                                 except
556                                 end;
557                                 Node := Node.GetNext;
558                         end;
559                 except
560                 end;
561         end;
562
563 end;
564
565 function TFavoriteDM.GetFavoriteFilePath() : String;
566 begin
567         Result := GikoSys.GetConfigDir + FAVORITE_FILE_NAME;
568 end;
569
570 end.