📄 usimedit.pas
字号:
unit uSIMEdit;
{
*******************************************************************************
* Descriptions: SIM Card Phonebook Edit Implementation
* $Source: /cvsroot/fma/fma/uSIMEdit.pas,v $
* $Locker: $
*
* Todo:
*
* Change Log:
* $Log: uSIMEdit.pas,v $
*
*******************************************************************************
}
interface
uses
Windows, TntWindows, Messages, SysUtils, TntSysUtils, Classes, TntClasses, Graphics, TntGraphics, Controls, TntControls,
Forms, TntForms, Dialogs, TntDialogs, Grids, TntComCtrls, TntGrids, ExtCtrls, TntExtCtrls, StdCtrls, TntStdCtrls, Math,
Menus, TntMenus, VirtualTrees, ImgList, uSyncPhonebook, uPromptConflict, uConflictChanges, Placemnt;
type
TSIMData = Record
imageindex: integer; {0=new,1=modified,2=deleted,3=normal}
position: integer;
cname,pnumb,ptype: WideString;
CDID: TGUID;
LUID : WideString;
end;
PSIMData = ^TSIMData;
TfrmContactsSMEdit = class(TTntFrame)
Panel1: TTntPanel;
btnUpdateSIM: TTntButton;
cbForce: TTntCheckBox;
btnReset: TTntButton;
PopupMenu1: TTntPopupMenu;
Clear1: TTntMenuItem;
Resetchangeflag1: TTntMenuItem;
ListNumbers: TVirtualStringTree;
NoItemsPanel: TTntPanel;
N1: TTntMenuItem;
N2: TTntMenuItem;
Properties1: TTntMenuItem;
NewPerson1: TTntMenuItem;
UpdateChanged1: TTntMenuItem;
UpdateAllRecords1: TTntMenuItem;
FormStorage1: TFormStorage;
N5: TTntMenuItem;
UpdateContactsPosition1: TTntMenuItem;
CopySelectedToPhone1: TTntMenuItem;
N4: TTntMenuItem;
ImportContacts1: TTntMenuItem;
ExportContacts1: TTntMenuItem;
OpenDialog1: TTntOpenDialog;
N3: TTntMenuItem;
MessageContact1: TTntMenuItem;
CallContact1: TTntMenuItem;
ChatContact1: TTntMenuItem;
N7: TTntMenuItem;
DownloadEntirePhonebook1: TTntMenuItem;
SendToPhone1: TTntMenuItem;
ForceAs1: TTntMenuItem;
otalChange1: TTntMenuItem;
Modified1: TTntMenuItem;
procedure Button1Click(Sender: TObject);
procedure StringGridGetEditText(Sender: TObject; ACol, ARow: Integer;
var Value: String);
procedure Resetchangeflag1Click(Sender: TObject);
procedure ListNumbersAfterPaint(Sender: TBaseVirtualTree;
TargetCanvas: TCanvas);
procedure ListNumbersCompareNodes(Sender: TBaseVirtualTree; Node1,
Node2: PVirtualNode; Column: TColumnIndex; var Result: Integer);
procedure ListNumbersGetImageIndex(Sender: TBaseVirtualTree;
Node: PVirtualNode; Kind: TVTImageKind; Column: TColumnIndex;
var Ghosted: Boolean; var ImageIndex: Integer);
procedure ListNumbersGetText(Sender: TBaseVirtualTree;
Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType;
var CellText: WideString);
procedure ListNumbersHeaderClick(Sender: TVTHeader;
Column: TColumnIndex; Button: TMouseButton; Shift: TShiftState; X,
Y: Integer);
procedure PopupMenu1Popup(Sender: TObject);
procedure NewPerson1Click(Sender: TObject);
procedure UpdateChanged1Click(Sender: TObject);
procedure UpdateAllRecords1Click(Sender: TObject);
procedure UpdateContactsPosition1Click(Sender: TObject);
procedure CopySelectedToPhone1Click(Sender: TObject);
procedure ListNumbersIncrementalSearch(Sender: TBaseVirtualTree;
Node: PVirtualNode; const SearchText: WideString;
var Result: Integer);
procedure ImportContacts1Click(Sender: TObject);
procedure DownloadEntirePhonebook1Click(Sender: TObject);
procedure ListNumbersKeyDown(Sender: TObject; var Key: Word;
Shift: TShiftState);
procedure FormStorage1SavePlacement(Sender: TObject);
procedure FormStorage1RestorePlacement(Sender: TObject);
procedure ListNumbersHeaderMouseUp(Sender: TVTHeader;
Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
procedure btnResetClick(Sender: TObject);
procedure btnUpdateSIMClick(Sender: TObject);
procedure btnDELClick(Sender: TObject);
procedure btnEDITClick(Sender: TObject);
procedure Modified1Click(Sender: TObject);
procedure frmSyncPhonebookNewNoUndo1Click(Sender: TObject);
private
{ Private declarations }
FContact: TContactData; // used for SIM contact editing (uEditContact)
FExplore: PVirtualNode; // remember last rendered data's explorer node
FOldText: String;
function IsUniqueGUID(who: PSIMData): boolean;
procedure FullRefresh;
procedure UpdateSIM(MaxItems: cardinal = 0);
procedure RenderGUIDs;
protected
{ Protected declarations }
FConflictPhone0,FConflictPhone1: string;
FConflictAnswer: integer;
FRendered: Boolean;
function GetCapacity(Target, LogName: string): Integer;
procedure DoForceSelectedAs(State: integer);
public
{ Public declarations }
SelContact: PSIMData;
FMaxNumbers: Cardinal;
FMaxNameLen,FMaxTelLen: integer;
constructor Create(AOwner: TComponent); override;
procedure UpdatePhonebook;
procedure OnConnected; virtual;
procedure ExportList(FileType:Integer; Filename: WideString); virtual;
function RenderData(ForceDBNode: PVirtualNode = nil): boolean;
function IsMEMode: boolean; virtual;
function IsRendered: boolean;
function FindFreePos(NodeData: TStrings = nil): integer;
function DoEdit(AsNew: boolean = False; NewNumber: string = ''): boolean;
function FindContact(Number: WideString): WideString; overload;
function FindContact(FullName: WideString; var AContact: PSIMData): boolean; overload;
function FindContact(FullName,NumberType: WideString; var AContact: PSIMData): boolean; overload;
function FindContact(FullName: WideString; var ANode: PVirtualNode): boolean; overload;
procedure CheckForChanges;
procedure UploadChangesToPhone(IsMEMode: boolean; var ListNumbers: TVirtualStringTree;
ModifiedCount, MaxNumbers, MaxNameLen: cardinal; UploadAll: boolean);
procedure CopySelectedToME;
procedure CopySelectedToIRMC;
procedure CopyContactsConflict(Sender: TObject; ContactName: WideString; const Description: WideString;
Phone0,Phone1: string; const Item0Name, Item1Name: WideString; var SelectedItem: Integer);
procedure OnConflictChanges(Sender: TObject; const TargetName, Option1Name, Option2Name: WideString);
procedure ResetConflictState;
end;
implementation
uses
gnugettext, gnugettexthelpers, cUnicodeCodecs,
uLogger, uThreadSafe, Unit1, uSMS, uGlobal, uEditContact, uConnProgress, uVcard, uXML, WebUtil, uDialogs;
{$R *.dfm}
{ TfrmContactsSMEdit }
constructor TfrmContactsSMEdit.Create(AOwner: TComponent);
begin
inherited;
{ Set defaults }
FMaxNameLen := 14; FMaxTelLen := 80; FMaxNumbers := 200;
FRendered := False;
end;
function TfrmContactsSMEdit.RenderData(ForceDBNode: PVirtualNode): boolean;
var
sl: TStrings;
s: WideString;
i: Integer;
contact: PSIMData;
Node: PVirtualNode;
EData: PFmaExplorerNode;
Modified,NeedRefresh: Boolean;
begin
ResetConflictState;
{ ForceDBNode is used when loading Profile database etc. }
if Assigned(ForceDBNode) then
FExplore := ForceDBNode
else
if Form1.ExplorerNew.FocusedNode = Form1.FNodeContactsME then
FExplore :=Form1.FNodeContactsME
else
FExplore :=Form1.FNodeContactsSM;
EData := Form1.ExplorerNew.GetNodeData(FExplore);
sl := EData.Data;
{ Load database }
Modified := False;
NeedRefresh := False;
ListNumbers.BeginUpdate;
try
ListNumbers.Clear;
ListNumbers.NodeDataSize := sizeof(TSIMData);
for i := 0 to sl.Count - 1 do begin
s := LongStringToWideString(sl[i]);
if Trim(s) = '' then continue;
{ process DB }
Node := ListNumbers.AddChild(nil);
try
contact := ListNumbers.GetNodeData(Node);
contact.cname := UTF8StringToWideString(HTMLDecode(WideStringToLongString(GetFirstToken(s))));
contact.pnumb := GetFirstToken(s);
contact.position := StrToInt(GetFirstToken(s));
if contact.position = 0 then NeedRefresh := True;
try
contact.imageindex := StrToInt(GetFirstToken(s));
except
contact.imageindex := 3; // 3 = not modified (new) item
Modified := True;
end;
try
contact.CDID := StringToGUID(GetFirstToken(s));
except
contact.CDID := NewGUID;
Modified := True;
end;
contact.LUID := GetFirstToken(s);
Form1.ExtractName(contact.cname,contact.ptype);
except
ListNumbers.DeleteNode(Node);
Log.AddMessageFmt(_('Database: Error loading data (DB Index %d)'), [i], lsError);
if FindCmdLineSwitch('FIXDB') then begin
sl[i] := '';
Log.AddMessageFmt(_('Database: Removed incorrect data (DB Index: %d)'), [i], lsInformation);
end;
end;
end;
RenderGUIDs;
FRendered := True;
finally
ListNumbers.EndUpdate;
ListNumbers.Sort(nil, ListNumbers.Header.SortColumn, ListNumbers.Header.SortDirection);
end;
if NeedRefresh then
Form1.Status(WideFormat(_('Please refresh %s from phone, because some contact positions are missing!'),
[EData.Text]));
Result := Modified;
end;
procedure TfrmContactsSMEdit.Button1Click(Sender: TObject);
begin
if not Form1.FConnected then Form1.ActionConnectionConnectExecute(Self);
Form1.ActionContactsDownloadExecute(Self);
RenderData;
end;
procedure TfrmContactsSMEdit.UpdateSIM(MaxItems: cardinal);
begin
UploadChangesToPhone(IsMEMode,ListNumbers,MaxItems,FMaxNumbers,FMaxNameLen,cbForce.Checked);
end;
procedure TfrmContactsSMEdit.btnUpdateSIMClick(Sender: TObject);
var
Item: PSIMData;
Node: PVirtualNode;
mcount,dcount,count: cardinal;
s,d: WideString;
begin
mcount := 0; dcount := 0;
Node := ListNumbers.GetFirst;
while Assigned(Node) do
try
item := ListNumbers.GetNodeData(Node);
if item.imageindex = 2 then
// deleted contact
inc(dcount)
else
// then process modified (or all) entries
if (item.imageindex <> 3) or cbForce.Checked then begin
{ Do sanity check for modified contacts }
if (Trim(item.cname) = '') and (Trim(item.pnumb) <> '') then
raise EConvertError.Create(Format(_('Please enter a contact name at position %s'),[IntToStr(item.position)]));
if (Trim(item.cname) <> '') and (Trim(item.pnumb) = '') then
raise EConvertError.Create(Format(_('Please enter a phone number at position %s'),[IntToStr(item.position)]));
if Length(item.cname) > FMaxNameLen then
raise EConvertError.Create(Format(_('The name at position %s is too long'),[IntToStr(item.position)]));
if Length(item.pnumb) > (FMaxTelLen+byte(Pos('+',item.pnumb) <> 0)) then
raise EConvertError.Create(Format(_('The number at position %s is too long'),[IntToStr(item.position)]));
inc(mcount);
end;
finally
Node := ListNumbers.GetNext(Node);
end;
count := mcount + dcount;
if count <> 0 then begin
if mcount <> 0 then
s := WideFormat(ngettext('%d modified contact', '%d modified contacts', mcount), [mcount])
else
s := '';
if dcount <> 0 then
d := WideFormat(ngettext('%d deleted contact', '%d deleted contacts', dcount), [dcount])
else
d := '';
if s <> '' then begin
if d <> '' then s := WideFormat('%s and %d',[s,d]);
end
else
s := d;
case MessageDlgW(WideFormat(_('Confirm sending %s to SIM card?'),[s]), mtConfirmation, MB_YESNOCANCEL) of
ID_YES: UpdateSIM(count);
ID_CANCEL: Abort;
end;
end;
end;
procedure TfrmContactsSMEdit.btnResetClick(Sender: TObject);
var
Item: PSIMData;
Node: PVirtualNode;
begin
ListNumbers.BeginUpdate;
Node := ListNumbers.GetFirst;
while Node <> nil do
try
item := ListNumbers.GetNodeData(Node);
item.imageindex := 3; // mark as not modified
finally
Node := ListNumbers.GetNext(Node);
end;
ListNumbers.EndUpdate;
UpdatePhonebook;
end;
procedure TfrmContactsSMEdit.StringGridGetEditText(Sender: TObject; ACol,
ARow: Integer; var Value: String);
begin
FOldText := Value;
end;
procedure TfrmContactsSMEdit.btnDELClick(Sender: TObject);
var
Item: PSIMData;
Node,Tmp: PVirtualNode;
s: WideString;
begin
if ListNumbers.SelectedCount = 0 then exit;
s := WideFormat(_('Deleting %d %s.'), [ListNumbers.SelectedCount,ngettext('contact','contacts',ListNumbers.SelectedCount)]);
if MessageDlgW(s+_(' Do you wish to continue?'), mtConfirmation, MB_YESNO or MB_DEFBUTTON2) <> ID_YES then
exit;
Form1.Status(s+'..');
ListNumbers.BeginUpdate;
try
Node := ListNumbers.GetFirst;
while Node <> nil do begin
if ListNumbers.Selected[Node] then begin
item := ListNumbers.GetNodeData(Node);
if item.imageindex <> 0 then begin
item.imageindex := 2;
end
else begin
Tmp := Node;
if Node <> ListNumbers.GetFirst then begin
Node := ListNumbers.GetPrevious(Node);
ListNumbers.DeleteNode(Tmp);
end
else begin
ListNumbers.DeleteNode(Tmp);
Node := ListNumbers.GetFirst;
continue;
end;
end;
end;
Node := ListNumbers.GetNext(Node);
end;
finally
ListNumbers.EndUpdate;
UpdatePhonebook;
end;
Form1.Status('');
end;
procedure TfrmContactsSMEdit.Resetchangeflag1Click(Sender: TObject);
begin
DoForceSelectedAs(3);
end;
function TfrmContactsSMEdit.GetCapacity(Target, LogName: string): Integer;
var
i: Integer;
buffer, stop: String;
slTmp: TStrings;
begin
Form1.TxAndWait('AT+CPBS="'+Target+'"'); // do not localize
Form1.TxAndWait('AT+CPBR=?'); // do not localize
// defaults
buffer := '';
stop := '200'; FMaxNameLen := 14; FMaxTelLen := 80;
// +CPBR: (1-200),80,14
for i := 0 to ThreadSafe.RxBuffer.Count-1 do
if Pos('+CPBR',ThreadSafe.RxBuffer.Strings[i]) = 1 then begin // do not localize
buffer := ThreadSafe.RxBuffer.Strings[i];
break;
end;
for i := 1 to length(buffer) do begin
if IsDelimiter('()-,', buffer, i) then buffer[i] := ' ';
end;
// +CPBR: 1 200 80 14
if buffer <> '' then begin
slTmp := TStringList.Create;
try
slTmp.DelimitedText := buffer;
stop := slTmp.Strings[2];
Log.AddMessage(LogName+': max entries = '+stop, lsDebug); // do not localize debug
FMaxTelLen := StrToInt(slTmp.Strings[3]);
Log.AddMessage(LogName+': max tel length = '+slTmp.Strings[3], lsDebug); // do not localize debug
FMaxNameLen := StrToInt(slTmp.Strings[4]);
Log.AddMessage(LogName+': max name length = '+slTmp.Strings[4], lsDebug); // do not localize debug
finally
slTmp.Free;
end;
end;
Result := StrToInt(stop);
end;
procedure TfrmContactsSMEdit.OnConnected;
begin
FMaxNumbers := GetCapacity('SM','SIM Book');
end;
procedure TfrmContactsSMEdit.ListNumbersAfterPaint(Sender: TBaseVirtualTree;
TargetCanvas: TCanvas);
begin
NoItemsPanel.Visible := ListNumbers.RootNodeCount = 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -