OSDN Git Service

bata62に更新
[gikonavigoeson/gikonavi.git] / Favorite.pas
index 0b6f6c5..2bca35d 100644 (file)
@@ -3,84 +3,275 @@ unit Favorite;
 interface
 
 uses
-       Messages, SysUtils, Classes, Contnrs, ComCtrls, {HttpApp,}
-       GikoSystem, XMLIntf, XMLDoc;
+       Messages, SysUtils, Classes, Contnrs, ComCtrls, {HttpApp,} YofUtils,
+       GikoSystem{, XMLIntf, XMLDoc}, GikoXMLDoc, BoardGroup, windows;
        {SAX, SAXHelpers, SAXComps, SAXKW;}
 
 type
        TFavoriteFolder = class
        end;
 
-       TFavoriteBoardItem = class
+       TFavoriteItem = class(TObject)
        private
-               FBBSID: string;
-               FBoardName: string;
+               FURL                            : string;
+               FTitle                  : string;
        public
-               property BBSID: string read FBBSID write FBBSID;
-               property BoardName: string read FBoardName write FBoardName;
+               function GetItemTitle : string; virtual;abstract;
+               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é
+               property Title                  : string        read FTitle write FTitle;
+       end;
+       TFavoriteBoardItem = class(TFavoriteItem)
+       private
+               FItem                           : TBoard;
+               function        GetItem : TBoard;
+       public
+               constructor Create( inURL : string; inTitle : string = ''; inItem : TBoard = nil );
+               constructor CreateWithItem( inItem : TBoard );
+               destructor Destory;
+               function GetItemTitle : string; override;
+               property Item                           : TBoard        read GetItem write FItem;
        end;
 
-       TFavoriteThreadItem = class
+       TFavoriteThreadItem = class(TFavoriteItem)
        private
-               FBBSID: string;
-               FThreadID: string;
-               FThreadName: string;
+               FItem                           : TThreadItem;
+               function        GetItem : TThreadItem;
        public
-               property BBSID: string read FBBSID write FBBSID;
-               property ThreadID: string read FThreadID write FThreadID;
-               property ThreadName: string read FThreadName write FThreadName;
+               constructor Create( inURL : string; inTitle : string = ''; inItem : TThreadItem = nil );
+               constructor CreateWithItem( inItem : TThreadItem );
+               destructor Destory;
+               function GetItemTitle : string; override;
+               property Item                           : TThreadItem   read GetItem write FItem;
        end;
 
        TFavoriteDM = class(TDataModule)
-               procedure DataModuleCreate(Sender: TObject);
-               procedure DataModuleDestroy(Sender: TObject);
        private
                { Private \90é\8c¾ }
-               FStack: TStack;
+        FAbEnd: Boolean;
                FTreeView: TTreeView;
-
-               procedure ReadNode(Node: IXMLNode);
-//             procedure AddSaveString(Node: TTreeNode; SaveList: TStringList);
-               procedure AddSaveString(Node: TTreeNode; XMLNode: IXMLNode);
-//             procedure SAXStartDocument(Sender: TObject);
-//             procedure SAXEndDocument(Sender: TObject);
-//             procedure SAXStartElement(Sender: TObject; const NamespaceURI, LocalName, QName: SAXString; const Atts: IAttributes);
-//             procedure SAXEndElement(Sender: TObject; const NamespaceURI, LocalName, QName: SAXString);
-//             procedure SAXCharacters(Sender: TObject; const PCh: SAXString);
+               FModified: boolean;
+               procedure ReadNode(Node: IXMLNode; Stack: TStack; TreeView: TTreeView);
+               procedure AddSaveString(Node: TTreeNode; SaveList: TStringList);
        public
                { Public \90é\8c¾ }
+               procedure Clear;
+               function GetFavoriteFilePath() : String;
+               function SaveFavoriteFile(FileName: String) : Boolean;
                procedure SetFavTreeView(TreeView: TTreeView);
                procedure ReadFavorite;
                procedure WriteFavorite;
+               procedure URLReplace(oldURLs: TStringList; newURLs: TStringList);
                property TreeView: TTreeView read FTreeView;
+               property Modified: boolean read FModified write FModified;
+        property AbEnd: Boolean read FAbEnd write FAbEnd;
        end;
 
 var
        FavoriteDM: TFavoriteDM;
 const
        FAVORITE_LINK_NAME = '\83\8a\83\93\83N';
+       FAVORITE_FILE_NAME = 'Favorite.xml';
 
 implementation
 
+uses   ExternalBoardManager, ExternalBoardPlugInMain,  MojuUtils;
+
 const
        FAVORITE_ROOT_NAME = '\82¨\8bC\82É\93ü\82è';
-       FAVORITE_FILE_NAME = 'Favorite.xml';
+
 
 {$R *.dfm}
 
-procedure TFavoriteDM.DataModuleCreate(Sender: TObject);
+constructor TFavoriteBoardItem.Create(
+       inURL           : string;
+       inTitle : string = '';
+       inItem  : TBoard = nil
+);
 begin
-       //FTreeView := TreeView;
-       //FTreeView := GikoForm.FavoriteTreeView;
+
+       inherited Create;
+
+       URL             := inURL;
+       Title   := inTitle;
+       Item    := inItem;
+
 end;
 
-procedure TFavoriteDM.DataModuleDestroy(Sender: TObject);
+constructor TFavoriteBoardItem.CreateWithItem(
+       inItem  : TBoard
+);
+begin
+
+       Create( inItem.URL, inItem.Title, inItem );
+
+end;
+destructor TFavoriteBoardItem.Destory;
+begin
+       if FItem <> nil then
+               FItem.Free;
+       inherited;
+end;
+//! \95Û\8e\9d\82µ\82Ä\82¢\82é\94Â\82Ì\83^\83C\83g\83\8b\82ð\95Ô\82·
+function TFavoriteBoardItem.GetItemTitle : string;
+begin
+       Result := '';
+       //\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
+       //\82Ì\82Æ\82«\82ÉFItem\82ªnil\82È\82Ì\82Å\82»\82Ì\82Æ\82«\82Í\82×\82Á\82Æ\8c\9f\8dõ
+       if FItem = nil then begin
+               FItem := BBSsFindBoardFromURL(URL);
+       end;
+       if FItem <> nil then begin
+               try
+                       if not FItem.IsThreadDatRead then begin
+                               GikoSys.ReadSubjectFile(FItem);
+                       end;
+               except
+               end;
+               Result := FItem.Title;
+       end;
+end;
+function       TFavoriteBoardItem.GetItem : TBoard;
 var
-       i: Integer;
+       protocol, host, path, document, port, bookmark : string;
+       BBSID   : string;
+       tmpURL  : string;
+begin
+
+       if FItem = nil then begin
+               FItem := BBSsFindBoardFromURL( URL );
+               if FItem = nil then begin
+                       tmpURL := URL;
+                       GikoSys.ParseURI( tmpURL, protocol, host, path, document, port, bookmark );
+                       if GikoSys.Is2chHost( host ) then begin
+                               BBSID := GikoSys.URLToID( tmpURL );
+                               FItem := BBSs[ 0 ].FindBBSID( BBSID );
+                               if FItem <> nil then
+                                       URL := FItem.URL;
+                       end;
+                       {
+                       // \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¯
+                       FItem                           := GikoSys.GetUnknownBoard( nil, URL );
+                       FItem.Title     := Title;
+                       }
+               end;
+       end;
+
+       Result := FItem;
+
+end;
+
+constructor TFavoriteThreadItem.Create(
+       inURL           : string;
+       inTitle : string = '';
+       inItem  : TThreadItem = nil
+);
+begin
+
+       inherited Create;
+       URL             := inURL;
+
+       Title   := inTitle;
+       Item    := inItem;
+
+end;
+
+constructor TFavoriteThreadItem.CreateWithItem(
+       inItem  : TThreadItem
+);
+begin
+
+       Create( inItem.URL, inItem.Title, inItem );
+
+end;
+destructor TFavoriteThreadItem.Destory;
+begin
+       if FItem <> nil then
+       FItem.Free;
+    inherited;
+end;
+//! \95Û\8e\9d\82µ\82Ä\82¢\82é\83X\83\8c\82Ì\83^\83C\83g\83\8b\82ð\95Ô\82·
+function TFavoriteThreadItem.GetItemTitle : string;
+begin
+       Result := '';
+       if FItem = nil then begin
+               FItem := BBSsFindThreadFromURL(URL);
+       end;
+       if FItem <> nil then begin
+               Result := FItem.Title;
+       end;
+end;
+
+function       TFavoriteThreadItem.GetItem : TThreadItem;
+var
+       board                                   : TBoard;
+       boardURL                        : string;
+       browsableURL    : string;
+       protocol, host, path, document, port, bookmark : string;
+       BBSID, BBSKey   : string;
+       tmpURL                          : string;
+begin
+
+       Result := nil;
+       if FItem = nil then begin
+               browsableURL    := GikoSys.GetBrowsableThreadURL( URL );
+               boardURL                        := GikoSys.GetThreadURL2BoardURL( browsableURL );
+               board                                   := BBSsFindBoardFromURL( boardURL );
+
+               if board = nil then begin
+                       tmpURL := URL;
+                       GikoSys.ParseURI( tmpURL, protocol, host, path, document, port, bookmark );
+                       if GikoSys.Is2chHost( host ) then begin
+                               GikoSys.Parse2chURL( tmpURL, path, document, BBSID, BBSKey );
+                               board := BBSs[ 0 ].FindBBSID( BBSID );
+                       end;
+
+                       if board = nil then begin
+                               Exit;
+                               // \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¯
+                               //board := GikoSys.GetUnknownBoard( nil, boardURL )
+                       end;
+               end;
+
+               FItem := board.FindThreadFromURL( browsableURL );
+
+               if FItem = nil then begin
+                       tmpURL := URL;
+                       GikoSys.ParseURI( tmpURL, protocol, host, path, document, port, bookmark );
+                       if GikoSys.Is2chHost( host ) then begin
+                               GikoSys.Parse2chURL( tmpURL, path, document, BBSID, BBSKey );
+                               FItem := BBSs[ 0 ].FindThreadItem( BBSID, BBSKey + '.dat' );
+                               if FItem <> nil then
+                                       URL := FItem.URL;
+                       end;
+               end;
+
+               if FItem = nil then begin
+                       FItem := TThreadItem.Create( board.BoardPlugIn, board, browsableURL );
+
+                       FItem.Title := Title;
+                       board.Add( FItem );
+               end;
+       end;
+
+       Result := FItem;
+
+end;
+
+procedure TFavoriteDM.Clear;
+var
+       Node    : TTreeNode;
 begin
-       for i := 0 to TreeView.Items.Count - 1 do begin
-               TObject(TreeView.Items[i].Data).Free;
+       TreeView.Items.BeginUpdate;
+       Node    := TreeView.Items.GetFirstNode;
+       while Node <> nil do begin
+               if TObject(Node.Data) <> nil then
+                               TObject(Node.Data).Free;
+               Node := Node.GetNext;
        end;
+               TreeView.Items.Clear;
+               TreeView.Items.EndUpdate;
+
+    FavoriteDM.Modified := true;
 end;
 
 procedure TFavoriteDM.SetFavTreeView(TreeView: TTreeView);
@@ -89,10 +280,6 @@ begin
 end;
 
 procedure TFavoriteDM.ReadFavorite;
-{var
-       FileName: string;
-       Node: TTreeNode;
-       FavFolder: TFavoriteFolder;}
 var
        FileName: string;
        XMLDoc: IXMLDocument;
@@ -101,64 +288,59 @@ var
        i: Integer;
        FavFolder: TFavoriteFolder;
        LinkExists: Boolean;
+    Stack: TStack;
 begin
+    FABend := False;
+    
+       FavoriteDM.Modified := true;
        FileName := GikoSys.GetConfigDir + FAVORITE_FILE_NAME;
 
        FavFolder := TFavoriteFolder.Create;
-       Node := FTreeView.Items.AddChildObject(nil, FAVORITE_ROOT_NAME, FavFolder);
-       Node.ImageIndex := 12;
-       Node.SelectedIndex := 13;
+       Node := FTreeView.Items.AddChildObjectFirst(nil, FAVORITE_ROOT_NAME, FavFolder);
+       Node.ImageIndex := 14;
+       Node.SelectedIndex := 14;
 
        if FileExists(FileName) then begin
-               XMLDoc := LoadXMLDocument(FileName);
-               XMLNode := XMLDoc.DocumentElement;
-
-               FStack := TStack.Create;
                try
-                       FStack.Push(Node);
-                       LinkExists := False;
-                       if XMLNode.NodeName = 'favorite' then begin
-                               for i := 0 to XMLNode.ChildNodes.Count - 1 do begin
-                                       ReadNode(XMLNode.ChildNodes[i]);
-                                       if (XMLNode.ChildNodes[i].NodeName = 'folder') and
-                                                (XMLNode.ChildNodes[i].Attributes['title'] = FAVORITE_LINK_NAME) then begin
-                                               LinkExists := True;
+            XMLDoc := IXMLDocument.Create;
+                       //XMLDoc := LoadXMLDocument(FileName);
+            LoadXMLDocument(FileName, XMLDoc);
+                       XMLNode := XMLDoc.DocumentElement;
+
+                       Stack := TStack.Create;
+                       try
+                               Stack.Push(Node);
+                               LinkExists := False;
+                               if XMLNode.NodeName = 'favorite' then begin
+                                       for i := XMLNode.ChildNodes.Count - 1 downto 0 do begin
+                                               ReadNode(XMLNode.ChildNodes[i], Stack, FTreeView);
+                                               if (XMLNode.ChildNodes[i].NodeName = 'folder') and
+                                                        (XMLNode.ChildNodes[i].Attributes['title'] = FAVORITE_LINK_NAME) then begin
+                                                       LinkExists := True;
+                                               end;
                                        end;
                                end;
+                               if not LinkExists then begin
+                                       FavFolder := TFavoriteFolder.Create;
+                                       Node := FTreeView.Items.AddChildObjectFirst(Node, FAVORITE_LINK_NAME, FavFolder);
+                                       Node.ImageIndex := 14;
+                                       Node.SelectedIndex := 14;
+                               end;
+
+                       finally
+                               Stack.Free;
+                XMLDoc.Free;
                        end;
-                       if not LinkExists then begin
-                               FavFolder := TFavoriteFolder.Create;
-                               Node := FTreeView.Items.AddChildObject(Node, FAVORITE_LINK_NAME, FavFolder);
-                               Node.ImageIndex := 12;
-                               Node.SelectedIndex := 13;
-                       end;
-               finally
-                       FStack.Free;
+               except
+            on e : Exception do begin
+                FABend := True;
+            end;
                end;
        end;
 
-{      FavFolder := TFavoriteFolder.Create;
-       Node := FTreeView.Items.AddChildObject(nil, FAVORITE_ROOT_NAME, FavFolder);
-       Node.ImageIndex := 12;
-       Node.SelectedIndex := 13;
-
-       FileName := GikoSys.GetConfigDir + FAVORITE_FILE_NAME;
-       if not FileExists(FileName) then
-               Exit;
-
-               FavSAXHandler.OnStartDocument := SAXStartDocument;
-               FavSAXHandler.OnEndDocument := SAXEndDocument;
-               FavSAXHandler.OnStartElement := SAXStartElement;
-               FavSAXHandler.OnStartElement := SAXStartElement;
-               FavSAXHandler.OnEndElement := SAXEndElement;
-               FavSAXHandler.OnCharacters := SAXCharacters;
-
-               FavSAXReader.Vendor := 'Keith Wood';
-               FavSAXReader.URL := FileName;
-               FavSAXReader.Parse;}
 end;
 
-procedure TFavoriteDM.ReadNode(Node: IXMLNode);
+procedure TFavoriteDM.ReadNode(Node: IXMLNode; Stack: TStack; TreeView: TTreeView);
 var
        i: Integer;
 
@@ -167,206 +349,239 @@ var
        FavFolder: TFavoriteFolder;
        FavBoard: TFavoriteBoardItem;
        FavThread: TFavoriteThreadItem;
+       board                           : TBoard;
+       threadItem      : TThreadItem;
 begin
        if Node.NodeName = 'folder' then begin
-               ParentNode := FStack.Peek;
+        CurrentNode := nil;
+               ParentNode := Stack.Peek;
                if TObject(ParentNode.Data) is TFavoriteFolder then begin
                        FavFolder := TFavoriteFolder.Create;
-                       CurrentNode := FTreeView.Items.AddChildObject(ParentNode, Node.Attributes['title'], FavFolder);
-                       CurrentNode.ImageIndex := 12;
-                       CurrentNode.SelectedIndex := 13;
-                       FStack.Push(CurrentNode);
+                       CurrentNode := TreeView.Items.AddChildObjectFirst(ParentNode, Node.Attributes['title'], FavFolder);
+                       CurrentNode.ImageIndex := 14;
+                       CurrentNode.SelectedIndex := 14;
+                       Stack.Push(CurrentNode);
                end;
-               for i := 0 to Node.ChildNodes.Count - 1 do begin
-                       ReadNode(Node.ChildNodes[i]);
+               for i := Node.ChildNodes.Count - 1 downto 0 do begin
+                       ReadNode(Node.ChildNodes[i], Stack, TreeView);
                end;
-               if FStack.Count <> 0 then
-                       FStack.Pop;
+               if CurrentNode <> nil then
+                       CurrentNode.Expanded := Node.Attributes[ 'expanded' ] = 'true';
+               if Stack.Count <> 0 then
+                       Stack.Pop;
        end else if Node.NodeName = 'favitem' then begin
-               ParentNode := FStack.Peek;
-               if TObject(ParentNode.Data) is TFavoriteFolder then begin
-                       if Node.Attributes['favtype'] = 'board' then begin
-                               FavBoard := TFavoriteBoardItem.Create;
-                               FavBoard.BBSID := Node.Attributes['bbs'];
-                               FavBoard.BoardName := Node.Attributes['boardname'];
-                               CurrentNode := FTreeView.Items.AddChildObject(ParentNode, Node.Attributes['title'], FavBoard);
-                               CurrentNode.ImageIndex := 14;
-                               CurrentNode.SelectedIndex := 15;
-                       end else if Node.Attributes['favtype'] = 'thread' then begin
-                               FavThread := TFavoriteThreadItem.Create;
-                               FavThread.BBSID := Node.Attributes['bbs'];
-                               FavThread.ThreadID := Node.Attributes['thread'];
-                               FavThread.ThreadName := Node.Attributes['threadname'];
-                               CurrentNode := FTreeView.Items.AddChildObject(ParentNode, Node.Attributes['title'], FavThread);
-                               CurrentNode.ImageIndex := 16;
-                               CurrentNode.SelectedIndex := 17;
+               try
+                       ParentNode := Stack.Peek;
+                       if TObject(ParentNode.Data) is TFavoriteFolder then begin
+                               if Node.Attributes['favtype'] = 'board' then begin
+                                       FavBoard := nil;
+                                       // \8b\8c\8e®\82Ì\82¨\8bC\82É\93ü\82è\82Æ\82Ì\8cÝ\8a·\90«\82Ì\82½\82ß
+                                       if Length( Node.Attributes[ 'bbs' ] ) > 0 then begin
+                                               board := BBSsFindBoardFromBBSID( Node.Attributes[ 'bbs' ] );
+                                               if board <> nil then
+                                                       FavBoard := TFavoriteBoardItem.Create(
+                                                               board.URL, MojuUtils.UnSanitize(Node.Attributes[ 'title' ]), board );
+                                       end else begin
+                                               FavBoard := TFavoriteBoardItem.Create(
+                                                       Node.Attributes[ 'url' ], MojuUtils.UnSanitize(Node.Attributes[ 'title' ]), nil );
+                                       end;
+                                       CurrentNode := TreeView.Items.AddChildObjectFirst(ParentNode, UnSanitize(Node.Attributes['title']), FavBoard);
+                                       CurrentNode.ImageIndex := 15;
+                                       CurrentNode.SelectedIndex := 15;
+                               end else if Node.Attributes['favtype'] = 'thread' then begin
+                                       // \8b\8c\8e®\82Ì\82¨\8bC\82É\93ü\82è\82Æ\82Ì\8cÝ\8a·\90«\82Ì\82½\82ß
+                                       if Length( Node.Attributes[ 'bbs' ] ) > 0 then begin
+                                               board := BBSsFindBoardFromBBSID( Node.Attributes[ 'bbs' ] );
+                                               if board = nil then
+                                                       Exit;
+
+                                               if not board.IsThreadDatRead then
+                                                       GikoSys.ReadSubjectFile( board );
+                                               threadItem := board.FindThreadFromFileName( Node.Attributes[ 'thread' ] );
+                                               if threadItem = nil then begin
+                                                       threadItem := TThreadItem.Create(
+                                                               board.BoardPlugIn,
+                                board,
+                                                               GikoSys.Get2chBoard2ThreadURL( board, ChangeFileExt( Node.Attributes[ 'thread' ], '' ) ) );
+                                                       threadItem.Title := UnSanitize(Node.Attributes[ 'title' ]);
+                                                       board.Add( threadItem );
+                                               end;
+                                               FavThread := TFavoriteThreadItem.Create(
+                                                       threadItem.URL, UnSanitize(Node.Attributes[ 'title' ]), threadItem );
+                        threadItem.Free;
+                                       end else begin
+                                               FavThread := TFavoriteThreadItem.Create(
+                                                       Node.Attributes[ 'url' ], UnSanitize(Node.Attributes[ 'title' ]), nil );
+                                       end;
+                                       CurrentNode := TreeView.Items.AddChildObjectFirst(ParentNode, UnSanitize(Node.Attributes['title']), FavThread);
+                                       CurrentNode.ImageIndex := 16;
+                                       CurrentNode.SelectedIndex := 16;
+                               end;
                        end;
+               except
+                       // \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Å
                end;
        end;
 end;
 
 procedure TFavoriteDM.WriteFavorite;
 var
-       FileName: string;
-//     SaveList: TStringList;
-//     i: Integer;
-//     Count: Integer;
-
-       XMLDoc: IXMLDocument;
-       XMLNode: IXMLNode;
-//     FavoNode: IXMLNode;
-begin
-       XMLDoc :=  NewXMLDocument;
-       XMLDoc.Encoding := 'Shift_JIS';
-       XMLDoc.StandAlone := 'yes';
-       XMLNode := XMLDoc.AddChild('favorite');
-       FileName := GikoSys.GetConfigDir + FAVORITE_FILE_NAME;
-       AddSaveString(TreeView.Items.GetFirstNode, XMLNode);
-       XMLDoc.SaveToFile(FileName);
-{var
-       FileName: string;
+       FileName, tmpFileName, bakFileName: string;
        SaveList: TStringList;
+    Buffer: array[0..MAX_PATH] of Char;   // \83o\83b\83t\83@
+    FileRep : Boolean;
 begin
+    FavoriteDM.Modified := true;
        FileName := GikoSys.GetConfigDir + FAVORITE_FILE_NAME;
        SaveList := TStringList.Create;
-       try
-               SaveList.Add('<?xml version="1.0" encoding="Shift_JIS" standalone="yes"?>');
-               SaveList.Add('<favorite>');
-               AddSaveString(TreeView.Items.GetFirstNode, SaveList);
-               SaveList.Add('</favorite>');
-               SaveList.SaveToFile(FileName);
-       finally
-               SaveList.Free;
-       end;}
-end;
-
-procedure TFavoriteDM.AddSaveString(Node: TTreeNode; XMLNode: IXMLNode);
-var
-       i: Integer;
-//     s: string;
-       FavBoard: TFavoriteBoardItem;
-       FavThread: TFavoriteThreadItem;
-       FavNode: IXMLNode;
-begin
-       for i := 0 to Node.Count - 1 do begin
-               if TObject(Node.Item[i].Data) is TFavoriteFolder then begin
-                       FavNode := XMLNode.AddChild('folder');
-                       FavNode.Attributes['title'] := Node.Item[i].Text;
-                       AddSaveString(Node.Item[i], FavNode);
-               end else if TObject(Node.Item[i].Data) is TFavoriteBoardItem then begin
-                       FavBoard := TFavoriteBoardItem(Node.Item[i].Data);
-                       FavNode := XMLNode.AddChild('favitem');
-                       FavNode.Attributes['type'] := '2ch';
-                       FavNode.Attributes['favtype'] := 'board';
-                       FavNode.Attributes['bbs'] := FavBoard.BBSID;
-                       FavNode.Attributes['title'] := Node.Item[i].Text;
-                       FavNode.Attributes['boardname'] := FavBoard.BoardName;
-               end else if TObject(Node.Item[i].Data) is TFavoriteThreadItem then begin
-                       FavThread := TFavoriteThreadItem(Node.Item[i].Data);
-                       FavNode := XMLNode.AddChild('favitem');
-                       FavNode.Attributes['type'] := '2ch';
-                       FavNode.Attributes['favtype'] := 'thread';
-                       FavNode.Attributes['bbs'] := FavThread.BBSID;
-                       FavNode.Attributes['thread'] := FavThread.ThreadID;
-                       FavNode.Attributes['title'] := Node.Item[i].Text;
-                       FavNode.Attributes['threadname'] := FavThread.ThreadName;
-               end;
-       end;
+    tmpFileName := '';
+    // \8f\91\82«\8d\9e\82Ý\97p\88ê\8e\9e\83t\83@\83C\83\8b\8eæ\93¾
+    if GetTempFileName(PChar(GikoSys.GetConfigDir), PChar('fav'), 0, Buffer) <> 0 then begin
+        tmpFileName := Buffer;
+        try
+            try
+                SaveList.Add('<?xml version="1.0" encoding="Shift_JIS" standalone="yes"?>');
+                SaveList.Add('<favorite>');
+                AddSaveString(TreeView.Items.GetFirstNode.getFirstChild, SaveList);
+                SaveList.Add('</favorite>');
+                // \88ê\8e\9e\83t\83@\83C\83\8b\82Æ\82µ\82Ä\95Û\91
+                SaveList.SaveToFile(tmpFileName);
+                FileRep := True;
+                // \91O\82Ì\83t\83@\83C\83\8b\82ð\88Ú\93®\82·\82é
+                if FileExists(FileName) then begin
+                    bakFileName := GikoSys.GetConfigDir + '~' + FAVORITE_FILE_NAME;
+                    if FileExists(bakFileName) then begin
+                        FileRep := SysUtils.DeleteFile(bakFileName); //SysUtils.\82ð\82Â\82¯\82È\82¢\82ÆWinAPI\82Æ\8bæ\95Ê\82Å\82«\82È\82¢\82Ì\82Å
+                    end;
+                    if FileRep then begin
+                        FileRep := RenameFile(FileName, bakFileName);
+                    end;
+                end;
+                // \90³\8bK\82Ì\83t\83@\83C\83\8b\96¼\82É\83\8a\83l\81[\83\80\82·\82é
+                if FileRep then begin
+                    FileRep := RenameFile(tmpFileName, FileName);
+                end;
+            except
+            end;
+        finally
+            SaveList.Free;
+        end;
+    end;
 end;
 
-{procedure TFavoriteDM.AddSaveString(Node: TTreeNode; SaveList: TStringList);
+procedure TFavoriteDM.AddSaveString(Node: TTreeNode; SaveList: TStringList);
 var
-       i: Integer;
        s: string;
        FavBoard: TFavoriteBoardItem;
        FavThread: TFavoriteThreadItem;
+       data : Pointer;
 begin
-       for i := 0 to Node.Count - 1 do begin
-               if TObject(Node.Item[i].Data) is TFavoriteFolder then begin
-                       s := Format('<folder title="%s">', [HtmlEncode(Node.Item[i].Text)]);
+       while Node <> nil do begin
+               data := Node.Data;
+               if TObject(data) is TFavoriteFolder then begin
+                       if Node.Expanded then
+                               s := Format('<folder title="%s" expanded="true">', [HtmlEncode(Node.Text)])
+                       else
+                               s := Format('<folder title="%s" expanded="false">', [HtmlEncode(Node.Text)]);
                        SaveList.Add(s);
-                       AddSaveString(Node.Item[i], SaveList);
+                       AddSaveString(Node.getFirstChild, SaveList);
                        SaveList.Add('</folder>');
-               end else if TObject(Node.Item[i].Data) is TFavoriteBoardItem then begin
-                       FavBoard := TFavoriteBoardItem(Node.Item[i].Data);
-                       s := Format('<favitem type="2ch" favtype="board" bbs="%s" title="%s" boardname="%s"/>',
-                                                                       [FavBoard.BBSID, HtmlEncode(Node.Item[i].Text), HtmlEncode(FavBoard.BoardName)]);
+               end else if TObject(data) is TFavoriteBoardItem then begin
+                       FavBoard := TFavoriteBoardItem(data);
+                       s := Format('<favitem type="2ch" favtype="board" url="%s" title="%s"/>',
+                                                                       [HtmlEncode( FavBoard.URL ), HtmlEncode(MojuUtils.Sanitize(Node.Text))]);
                        SaveList.Add(s);
-               end else if TObject(Node.Item[i].Data) is TFavoriteThreadItem then begin
-                       FavThread := TFavoriteThreadItem(Node.Item[i].Data);
-                       s := Format('<favitem type="2ch" favtype="thread" bbs="%s" thread="%s" title="%s" threadname="%s"/>',
-                                                                       [FavThread.BBSID, FavThread.ThreadID, HtmlEncode(Node.Item[i].Text), HtmlEncode(FavThread.ThreadName)]);
+               end else if TObject(data) is TFavoriteThreadItem then begin
+                       FavThread := TFavoriteThreadItem(data);
+                       s := Format('<favitem type="2ch" favtype="thread" url="%s" title="%s"/>',
+                                                                       [HtmlEncode( FavThread.URL ), HtmlEncode(MojuUtils.Sanitize(Node.Text))]);
                        SaveList.Add(s);
                end;
+               Node := Node.getNextSibling;
        end;
-end;}
-
-{
-procedure TFavoriteDM.SAXStartDocument(Sender: TObject);
-begin
-       FStack := TStack.Create;
-       FStack.Push(FTreeView.Items.GetFirstNode);
 end;
 
-procedure TFavoriteDM.SAXEndDocument(Sender: TObject);
+function TFavoriteDM.SaveFavoriteFile(FileName: String) : Boolean;
+var
+       FavoriteFilePath: string;
+               tempStringList: TStringList;
 begin
-       FStack.Free;
+       WriteFavorite;
+       FavoriteFilePath := GikoSys.GetConfigDir + FAVORITE_FILE_NAME;
+
+       if FileExists( FavoriteFilePath ) then begin
+               tempStringList := TStringList.Create;
+               try
+                       tempStringList.LoadFromFile( FavoriteFilePath );
+                       tempStringList.SaveToFile( FileName );
+               finally
+                       tempStringList.Free;
+               end;
+               Result := true;
+       end else begin
+               Result := false;
+       end;
 end;
 
-procedure TFavoriteDM.SAXStartElement(Sender: TObject; const NamespaceURI, LocalName, QName: SAXString;
-       const Atts: IAttributes);
+procedure TFavoriteDM.URLReplace(oldURLs: TStringList; newURLs: TStringList);
 var
-       FavType: string;
-       ParentNode: TTreeNode;
-       CurrentNode: TTreeNode;
-       FavFolder: TFavoriteFolder;
-       FavBoard: TFavoriteBoardItem;
-       FavThread: TFavoriteThreadItem;
+       i                                       : Integer;
+               tmpURL: string;
+    oldHost: string;
+    oldBoardName: string;
+    newHost: string;
+    newBoardName: string;
+               tempString: string;
+       favBoard        : TFavoriteBoardItem;
+       favThread       : TFavoriteThreadItem;
+       favorites       : TTreeNodes;
+       Node                    : TTreeNode;
 begin
-       if QName = 'folder' then begin
-               ParentNode := FStack.Peek;
-               if TObject(ParentNode.Data) is TFavoriteFolder then begin
-                       FavFolder := TFavoriteFolder.Create;
-                       CurrentNode := FTreeView.Items.AddChildObject(ParentNode, Atts.getValue('title'), FavFolder);
-                       CurrentNode.ImageIndex := 12;
-                       CurrentNode.SelectedIndex := 13;
-                       FStack.Push(CurrentNode);
-               end;
-       end else if QName = 'favitem' then begin
-               ParentNode := FStack.Peek;
-               if TObject(ParentNode.Data) is TFavoriteFolder then begin
-                       FavType := Atts.getValue('favtype');
-                       if FavType = 'board' then begin
-                               FavBoard := TFavoriteBoardItem.Create;
-                               FavBoard.BBSID := Atts.getValue('bbs');
-                               FavBoard.BoardName := Atts.getValue('boardname');
-                               CurrentNode := FTreeView.Items.AddChildObject(ParentNode, Atts.getValue('title'), FavBoard);
-                               CurrentNode.ImageIndex := 14;
-                               CurrentNode.SelectedIndex := 15;
-                       end else if FavType = 'thread' then begin
-                               FavThread := TFavoriteThreadItem.Create;
-                               FavThread.BBSID := Atts.getValue('bbs');
-                               FavThread.ThreadID := Atts.getValue('thread');
-                               FavThread.ThreadName := Atts.getValue('threadname');
-                               CurrentNode := FTreeView.Items.AddChildObject(ParentNode, Atts.getValue('title'), FavThread);
-                               CurrentNode.ImageIndex := 16;
-                               CurrentNode.SelectedIndex := 17;
+
+       // \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
+       favorites := FavoriteDM.FTreeView.Items;
+       for i := 0 to oldURLs.Count - 1 do begin
+               try
+                       tmpURL                  := Copy(oldURLs[i], 1, Length(oldURLs[i]) -1);
+                       oldHost                 := Copy(tmpURL, 1, LastDelimiter('/', tmpURL) );
+                       oldBoardName    := Copy(tmpURL, LastDelimiter('/', tmpURL), Length(tmpURL) ) + '/';
+                       tmpURL                  := Copy(newURLs[i], 1, Length(newURLs[i]) -1);
+                       newHost                 := Copy(tmpURL, 1, LastDelimiter('/', tmpURL) );
+                       newBoardName    := Copy(tmpURL, LastDelimiter('/', tmpURL), Length(tmpURL) ) + '/';
+
+                       Node := favorites.GetFirstNode.getFirstChild;
+                       while Node <> nil do begin
+                               try
+                                       if TObject( Node.Data ) is TFavoriteBoardItem then begin
+                                               favBoard := TFavoriteBoardItem( Node.Data );
+                                               if favBoard = nil then continue;
+                                               tempString := favBoard.URL;
+                                               if ( AnsiPos(oldBoardName, tempString) <> 0 ) and ( AnsiPos(oldHost, tempString ) <> 0 ) then begin
+                                                       tempString              := StringReplace(tempString, oldHost, newHost,[]);
+                                                       favBoard.URL    := tempString;
+                                               end;
+                                       end else if TObject( Node.Data ) is TFavoriteThreadItem then begin
+                                               favThread := TFavoriteThreadItem( Node.Data );
+                                               if favThread = nil then continue;
+                                               tempString := favThread.URL;
+                                               if ( AnsiPos(oldBoardName, tempString) <> 0 ) and ( AnsiPos(oldHost, tempString ) <> 0 ) then begin
+                                                       tempString              := StringReplace(tempString, oldHost, newHost,[]);
+                                                       favThread.URL   := tempString;
+                                               end;
+                                       end;
+                               except
+                               end;
+                               Node := Node.GetNext;
                        end;
+               except
                end;
        end;
-end;
 
-procedure TFavoriteDM.SAXEndElement(Sender: TObject; const NamespaceURI, LocalName, QName: SAXString);
-begin
-       if QName = 'folder' then begin
-               if FStack.Count <> 0 then
-                       FStack.Pop;
-       end;
 end;
 
-procedure TFavoriteDM.SAXCharacters(Sender: TObject; const PCh: SAXString);
+function TFavoriteDM.GetFavoriteFilePath() : String;
 begin
-//
+       Result := GikoSys.GetConfigDir + FAVORITE_FILE_NAME;
 end;
-}
+
 end.