usyncbookmarks.pas
来自「FMA is a free1 powerful phone editing to」· PAS 代码 · 共 1,240 行 · 第 1/3 页
PAS
1,240 行
unit uSyncBookmarks;
{
*******************************************************************************
* Descriptions: Phone Info view implementation
* $Source: /cvsroot/fma/fma/uSyncBookmarks.pas,v $
* $Locker: $
*
* Todo:
* - Create a custmo view for bookmarks, custom popup menu, custom Properties.
* - Add support for new phones K610 etc.
*
* Change Log:
* $Log: uSyncBookmarks.pas,v $
*
}
interface
uses
Windows, TntWindows, Messages, SysUtils, TntSysUtils, Variants, Classes, TntClasses, Graphics, TntGraphics,
Controls, TntControls, Forms, TntForms, Dialogs, TntDialogs, Placemnt, VirtualTrees, ExtCtrls, TntExtCtrls,
Menus, TntMenus, uConnProgress;
resourcestring
sHomePageLocked = 'Could not change WAP home page!'+sLinebreak+sLinebreak+
'In certain terminals a number of WAP profiles may be locked at '+
'manufacturing to prevent the users from altering the predefined WAP settings. When such a '+
'profile is active some of the commands in this ensemble will not function according to '+
'specification. The read and test commands should always function as expected but the set '+
'command will return ERROR even though the command is given using the correct syntax and '+
'all parameters are within range.';
type
TBookmarkStatus = (bsNew, bsModified, bsDeleted, bsNormal);
TBookmarkData = Record
status: TBookmarkStatus;
position: integer;
title,url: WideString;
id: TGUID; // HASH for original title and url values as loaded from phone first time!
// This will be used to detect any changes made in phone for that bookmark.
end;
PBookmarkData = ^TBookmarkData;
TfrmSyncBookmarks = class(TTntFrame)
ListBookmarks: TVirtualStringTree;
FormStorage1: TFormStorage;
NoItemsPanel: TTntPanel;
PopupMenu1: TTntPopupMenu;
Properties1: TTntMenuItem;
N1: TTntMenuItem;
Delete1: TTntMenuItem;
NewBookmark1: TTntMenuItem;
N3: TTntMenuItem;
OpenTargetLocation1: TTntMenuItem;
N5: TTntMenuItem;
DownloadEntireList1: TTntMenuItem;
N6: TTntMenuItem;
Import1: TTntMenuItem;
Export1: TTntMenuItem;
SyncTo1: TTntMenuItem;
InternetExplorer1: TTntMenuItem;
SetasHomePage1: TTntMenuItem;
N2: TTntMenuItem;
Firefox1: TTntMenuItem;
Opera1: TTntMenuItem;
WAPHomePage1: TTntMenuItem;
N8: TTntMenuItem;
SynchrinizePhone1: TTntMenuItem;
N4: TTntMenuItem;
N7: TTntMenuItem;
ForceAs1: TTntMenuItem;
NotModified1: TTntMenuItem;
Modified1: TTntMenuItem;
NewNoUndo1: TTntMenuItem;
procedure FormStorage1RestorePlacement(Sender: TObject);
procedure FormStorage1SavePlacement(Sender: TObject);
procedure ListBookmarksAfterPaint(Sender: TBaseVirtualTree;
TargetCanvas: TCanvas);
procedure ListBookmarksCompareNodes(Sender: TBaseVirtualTree; Node1,
Node2: PVirtualNode; Column: TColumnIndex; var Result: Integer);
procedure ListBookmarksGetImageIndex(Sender: TBaseVirtualTree;
Node: PVirtualNode; Kind: TVTImageKind; Column: TColumnIndex;
var Ghosted: Boolean; var ImageIndex: Integer);
procedure ListBookmarksGetText(Sender: TBaseVirtualTree;
Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType;
var CellText: WideString);
procedure ListBookmarksHeaderClick(Sender: TVTHeader;
Column: TColumnIndex; Button: TMouseButton; Shift: TShiftState; X,
Y: Integer);
procedure ListBookmarksHeaderMouseUp(Sender: TVTHeader;
Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
procedure ListBookmarksKeyDown(Sender: TObject; var Key: Word;
Shift: TShiftState);
procedure OpenTargetLocation1Click(Sender: TObject);
procedure PopupMenu1Popup(Sender: TObject);
procedure DownloadEntireList1Click(Sender: TObject);
procedure SetasHomePage1Click(Sender: TObject);
procedure SynchrinizePhone1Click(Sender: TObject);
procedure NotModified1Click(Sender: TObject);
procedure Modified1Click(Sender: TObject);
procedure NewNoUndo1Click(Sender: TObject);
procedure btnSYNCClick(Sender: TObject);
procedure btnNEWClick(Sender: TObject);
procedure btnEDITClick(Sender: TObject);
procedure btnDELClick(Sender: TObject);
private
{ Private declarations }
FRendered: boolean;
PhoneData: TBookmarkData;
FFmaBData: PBookmarkData;
FSyncDialog: TfrmConnect;
FMaxItems,FMaxTitleLen,FMaxUrlLen,FMaxHomeLen: Cardinal;
function GetBookmarksCapacity: Integer;
function GetHomePageCapacity: Integer;
function ResolveConflict(NameContact: WideString; Info:WideString): integer;
function Synchronize: boolean;
procedure GetPhoneBookmarks(var sl: TStringList);
procedure FullRefresh;
procedure ForceContact(State: TBookmarkStatus);
protected
procedure DoUploadBookmark(Item: PBookmarkData; DeleteOld: boolean = False);
procedure DoDeleteBookmark(Item: PBookmarkData);
public
{ Public declarations }
constructor Create(AOwner: TComponent); override;
procedure RenderList;
procedure UpdateBookmarks;
procedure OnConnected;
procedure LoadBookmarks(FileName:WideString);
procedure SaveBookmarks(FileName:WideString);
function FindBookmark(Position: integer; var Data: PBookmarkData): PVirtualNode;
function FindBookmarkID(AID: TGUID; var Data: PBookmarkData): PVirtualNode;
function FindBookmarkUrl(AURL: WideString; var Data: PBookmarkData): PVirtualNode;
function FindBookmarkTitle(ATitle: WideString; var Data: PBookmarkData): PVirtualNode;
function DoEdit(Node: PVirtualNode): boolean;
procedure OnConflictChanges(Sender: TObject; const TargetName, Option1Name, Option2Name: WideString);
published
property IsRendered: boolean read FRendered write FRendered;
property MaxHomePageLength: Cardinal read FMaxHomeLen;
end;
var
frmSyncBookmarks: TfrmSyncBookmarks;
function SameBookmarkIDs(Data1,Data2: PBookmarkData): boolean;
function IsThisBookmark(ID: TGUID; Data: PBookmarkData): boolean;
function IsBookmarkModified(Data: PBookmarkData): boolean;
function GetBookmarkNewID(Data: PBookmarkData): TGUID;
procedure SetBookmarkStatus(Data: PBookmarkData; Status: TBookmarkStatus);
implementation
{$R *.dfm}
uses
gnugettext, gnugettexthelpers, cUnicodeCodecs,
uLogger, ShellAPI, TntComCtrls, Unit1, uGlobal, uPostURL, uDialogs,
uInfoView, uPromptConflict, uThreadSafe, uConflictChanges, Math;
function SameBookmarkIDs(Data1,Data2: PBookmarkData): boolean;
begin
Result := CompareMem(@(Data1^.id),@(Data2^.id),SizeOf(Data1^.id));
end;
function IsThisBookmark(ID: TGUID; Data: PBookmarkData): boolean;
begin
Result := CompareMem(@ID,@(Data^.id),SizeOf(ID));
end;
function IsBookmarkModified(Data: PBookmarkData): boolean;
var
g: TGUID;
begin
g := GetBookmarkNewID(Data);
Result := not CompareMem(@g,@(Data^.id),SizeOf(g));
end;
function GetBookmarkNewID(Data: PBookmarkData): TGUID;
var
g: TGUID;
i,s: Integer;
w: WideString;
p: PChar;
begin
p := @g;
w := Data^.title + '|' + Data^.url;
s := SizeOf(g);
FillChar(g,s,0);
for i := 0 to Length(w) do begin
(p + i mod s)^ := PChar(@w[i])^;
end;
Result := g;
end;
procedure SetBookmarkStatus(Data: PBookmarkData; Status: TBookmarkStatus);
begin
case Status of
bsNew:
FillChar(Data^.id,SizeOf(Data^.id),0);
bsModified,
bsDeleted:
Data^.status := Status;
bsNormal:
Data^.id := GetBookmarkNewID(Data);
end;
end;
{ TfrmSyncBookmarks }
function TfrmSyncBookmarks.Synchronize: boolean;
var
sl: TStringList;
i: Integer;
g: TBookmarkData;
Item,Data: PBookmarkData;
Node: PVirtualNode;
PhoneOnPC,PhoneModified,PhoneDeleted: boolean;
PhoneSpecialMod: Set of Byte;
procedure UpdatePositions(PosDeleted: Integer);
var
Node: PVirtualNode;
Data: PBookmarkData;
bpos: byte;
begin
Node := ListBookmarks.GetFirst;
while Assigned(Node) do begin
Data := ListBookmarks.GetNodeData(Node);
if Assigned(Data) then
if Data.position > PosDeleted then begin
bpos := byte(Data.position);
if bpos in PhoneSpecialMod then
PhoneSpecialMod := PhoneSpecialMod - [bpos] + [bpos-1];
Data.position := Data.position-1;
end;
Node := ListBookmarks.GetNext(Node)
end;
end;
function LocalInPhone(Data: PBookmarkData): boolean;
var
bd: TBookmarkData;
begin
i := 0;
while i < sl.Count do begin
FillChar(bd,SizeOf(bd),0);
bd.status := bsNormal;
bd.position := StrToInt(GetToken(sl[i],0));
bd.url := GetToken(sl[i],1);
bd.title := UTF8StringToWideString(GetToken(sl[i],2));
bd.id := GetBookmarkNewID(@bd);
if SameBookmarkIDs(Data,@bd) then
break;
inc(i);
end;
Result := i < sl.Count;
end;
function DelAndGetNext(Node: PVirtualNode): PVirtualNode;
var
Prev: PVirtualNode;
begin
Prev := Node;
Result := ListBookmarks.GetNext(Node);
ListBookmarks.DeleteNode(Prev);
end;
procedure ShowProgressTarget(AName: WideString);
begin
if Assigned(FSyncDialog) then
FSyncDialog.SetDescr(_('Synchronizing phone bookmarks')+sLinebreak+'('+AName+')');
end;
begin
Result := False;
Form1.RequestConnection;
sl := TStringList.Create;
try
{ First process phone changes }
PhoneSpecialMod := [];
GetPhoneBookmarks(sl);
for i := 0 to sl.Count-1 do begin
FillChar(PhoneData,SizeOf(PhoneData),0);
PhoneData.status := bsNormal;
PhoneData.position := StrToInt(GetToken(sl[i],0));
PhoneData.url := GetToken(sl[i],1);
PhoneData.title := UTF8StringToWideString(WideStringToLongString(GetToken(LongStringToWideString(sl[i]),2)));
PhoneData.id := GetBookmarkNewID(@PhoneData);
Log.AddSynchronizationMessage('Debug: Processing phone bookmark '+PhoneData.title, lsDebug);
{ Locate Bookmark in FMA }
Node := FindBookmarkID(PhoneData.id,Data); // modified both title and url in FMA? (phone item not modified)
if not Assigned(Node) then
Node := FindBookmarkUrl(PhoneData.url,Data); // modified title in FMA?
if not Assigned(Node) then
Node := FindBookmarkTitle(PhoneData.title,Data); // modified url in FMA?
if not Assigned(Node) then begin
Node := FindBookmark(PhoneData.position,Data); // modified phone-title and fma-url? (or reverse)
if Assigned(Node) then begin
{ Try to lookup local bookmark using unchanged fields in both instances }
FillChar(g,SizeOf(g),0);
g.title := PhoneData.title;
g.url := Data.url;
g.id := GetBookmarkNewID(@g);
if not SameBookmarkIDs(@g,Data) then begin
g.title := Data.title;
g.url := PhoneData.url;
g.id := GetBookmarkNewID(@g);
if not SameBookmarkIDs(@g,Data) then
Node := nil;
end;
{ Remember fixed-changes positions, if any }
if Assigned(Node) then
PhoneSpecialMod := PhoneSpecialMod + [byte(PhoneData.position)];
end;
end;
{ Bookmark found? }
if Node <> nil then begin
{ yes, check if it is modified in phone }
PhoneModified := not SameBookmarkIDs(Data,@PhoneData); // Data.id = Hash of original phone values
if PhoneModified then
ShowProgressTarget(Data.title);
Data.position := PhoneData.position; // update bookmark position in phone
FFmaBData := nil; // used for conflicts details
case Data.status of
bsNew,
bsModified: begin
if PhoneModified then begin
FFmaBData := Data;
PhoneOnPC := ResolveConflict(Data.title, _('is modified on phone and modified on pc.')) = 0;
if PhoneOnPC then begin
Data^ := PhoneData;
SetBookmarkStatus(Data,bsNormal);
Log.AddSynchronizationMessage(Data.title + _(' modified in FMA by phone.'), lsInformation);
end;
end;
end;
bsDeleted: begin
if PhoneModified then begin
PhoneOnPC := ResolveConflict(Data.title, _('is modified on phone and deleted on pc.')) = 0;
if PhoneOnPC then begin
Data^ := PhoneData;
SetBookmarkStatus(Data,bsNormal);
Log.AddSynchronizationMessage(Data.title + _(' modified in FMA by phone.'), lsInformation);
end;
end;
end;
bsNormal: begin
if PhoneModified then begin
Data^ := PhoneData;
SetBookmarkStatus(Data,bsNormal);
Log.AddSynchronizationMessage(Data.title + _(' modified in FMA by phone.'), lsInformation);
end;
end;
end;
end
else begin
{ no, it is a new bookmark in phone }
ShowProgressTarget(PhoneData.title);
Node := ListBookmarks.AddChild(nil);
Item := ListBookmarks.GetNodeData(Node);
Item^ := PhoneData;
SetBookmarkStatus(Item,bsNormal);
Log.AddSynchronizationMessage(PhoneData.title + _(' added to FMA by phone.'), lsInformation);
end;
end;
{ Next process FMA changes }
Node := ListBookmarks.GetFirst;
while Assigned(Node) do begin
Data := ListBookmarks.GetNodeData(Node);
if Assigned(Data) then begin
Log.AddSynchronizationMessage('Debug: Processing FMA bookmark '+Data.title, lsDebug);
{ if we're checking mixed-changed position, it is in Phone for sure }
if byte(Data.position) in PhoneSpecialMod then
PhoneDeleted := False
else
{ check if bookmark is deleted in phone? }
PhoneDeleted := not LocalInPhone(Data);
if PhoneDeleted or (Data.status <> bsNormal) then
ShowProgressTarget(Data.title);
FFmaBData := nil; // used for conflicts details
case Data.status of
bsNew: begin
DoUploadBookmark(Data);
SetBookmarkStatus(Data,bsNormal);
Log.AddSynchronizationMessage(Data.title + _(' added in phone by FMA.'), lsInformation);
end;
bsModified: begin
if PhoneDeleted then begin
PhoneOnPC := ResolveConflict(Data.title, _('is deleted on phone and modified on pc.')) = 0;
if PhoneOnPC then begin
Node := DelAndGetNext(Node);
Log.AddSynchronizationMessage(Data.title + _(' deleted in FMA by phone.'), lsInformation);
continue;
end;
end;
DoUploadBookmark(Data,not PhoneDeleted);
SetBookmarkStatus(Data,bsNormal);
if PhoneDeleted then
Log.AddSynchronizationMessage(Data.title + _(' added in phone by FMA.'), lsInformation)
else begin
UpdatePositions(Data.position);
Log.AddSynchronizationMessage(Data.title + _(' modified in phone by FMA.'), lsInformation);
end;
end;
bsDeleted: begin
if not PhoneDeleted then begin
DoDeleteBookmark(Data);
SetBookmarkStatus(Data,bsNormal);
UpdatePositions(Data.position);
end;
Node := DelAndGetNext(Node);
if not PhoneDeleted then
Log.AddSynchronizationMessage(Data.title + _(' deleted in phone by FMA.'), lsInformation);
continue;
end;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?