You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
911 lines
24 KiB
Plaintext
911 lines
24 KiB
Plaintext
{
|
|
This file is part of R&Q.
|
|
Under same license
|
|
}
|
|
unit HistAllSearch;
|
|
{$I RnQConfig.inc}
|
|
|
|
interface
|
|
|
|
uses
|
|
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Types, Generics.Collections, Vcl.AppEvnts, Vcl.Menus,
|
|
StdCtrls, ExtCtrls, RnQGlobal, RnQButtons, VirtualTrees, DateUtils, Threading,
|
|
Sciter, SciterAPI, GR32, ICQCommon, ICQContacts, ICQConsts, ICQSession, ChatBox, history;
|
|
|
|
{$I NoRTTI.inc}
|
|
|
|
const
|
|
WM_AFTERSHOW = WM_USER + 1;
|
|
|
|
type
|
|
TAllHistSrchForm = class(TForm)
|
|
split: TSplitter;
|
|
pnl: TPanel;
|
|
caseChk: TCheckBox;
|
|
RoasterChk: TCheckBox;
|
|
SchAllBtn: TRnQButton;
|
|
SchBtn: TRnQButton;
|
|
direction: TComboBox;
|
|
HistPosTree: TVirtualDrawTree;
|
|
radioAll: TRadioButton;
|
|
radioCurrent: TRadioButton;
|
|
HistPosTreeAll: TVirtualDrawTree;
|
|
loading: TPanel;
|
|
AppEvents: TApplicationEvents;
|
|
SearchEdit: TEdit;
|
|
HistMenu: TPopupMenu;
|
|
Copy1: TMenuItem;
|
|
procedure SchAllBtnClick(Sender: TObject);
|
|
procedure HistPosTreeFreeNode(Sender: TBaseVirtualTree; Node: PVirtualNode);
|
|
procedure FormCreate(Sender: TObject);
|
|
procedure HistPosTreeDrawNode(Sender: TBaseVirtualTree; const PaintInfo: TVTPaintInfo);
|
|
procedure FormShow(Sender: TObject);
|
|
procedure FormAfterShow(var Msg: TMessage); message WM_AFTERSHOW;
|
|
procedure DoAfterShow;
|
|
procedure FormClose(Sender: TObject; var Action: TCloseAction);
|
|
procedure SchBtnClick(Sender: TObject);
|
|
procedure FormResize(Sender: TObject);
|
|
procedure keyEvent(Sender: TObject; var Key: Char);
|
|
procedure OpenPreview(Node: PVirtualNode);
|
|
procedure updateSearchFrmXY;
|
|
procedure applyFormXY;
|
|
procedure radioAllClick(Sender: TObject);
|
|
procedure radioCurrentClick(Sender: TObject);
|
|
procedure SwitchSource(srcAll: Boolean);
|
|
procedure HistPosTreeAllDrawNode(Sender: TBaseVirtualTree; const PaintInfo: TVTPaintInfo);
|
|
procedure HistPosTreeChange(Sender: TBaseVirtualTree; Node: PVirtualNode);
|
|
procedure UpdateChatSettings;
|
|
procedure UpdateChatSmiles;
|
|
procedure LoadHistory;
|
|
procedure SelectTarget;
|
|
procedure MeasureHeight(doAll: Boolean = False);
|
|
procedure HistPosTreeAllNodeDblClick(Sender: TBaseVirtualTree; const HitInfo: THitInfo);
|
|
procedure HistPosTreeScroll(Sender: TBaseVirtualTree; DeltaX, DeltaY: Integer);
|
|
procedure AppEventsMessage(var Msg: tagMSG; var Handled: Boolean);
|
|
procedure HistPosTreeMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
|
|
procedure HistPosTreeKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
|
|
procedure FormDestroy(Sender: TObject);
|
|
procedure Copy1Click(Sender: TObject);
|
|
procedure HistPosTreeResize(Sender: TObject);
|
|
private
|
|
{ Private declarations }
|
|
stop2search: Boolean;
|
|
thisProto: TICQSession;
|
|
procedure CopySelectedNodes;
|
|
public
|
|
{ Public declarations }
|
|
contact: TICQContact;
|
|
all: Boolean;
|
|
targetTime: TDateTime;
|
|
ChatBox: TChatBox;
|
|
end;
|
|
|
|
var
|
|
AllHistSrchForm: TAllHistSrchForm;
|
|
Task: ITask;
|
|
HistWidth: Integer;
|
|
bmps: array of TBitmap32;
|
|
DC: HDC;
|
|
|
|
implementation
|
|
|
|
{$R *.dfm}
|
|
|
|
uses
|
|
StrUtils, Clipbrd, RDFileUtil, RQUtil, RDGlobal, RnQLangs, RQThemes,
|
|
RnQSysUtils, RnQPics, RnQDialogs, chatDlg, events, globalLib, themesLib, utilLib, SciterLib;
|
|
|
|
type
|
|
PHSItem = ^THSItem;
|
|
|
|
THSItem = record
|
|
NodeType: (NT_MY, NT_HIS, NT_UID, NT_POSITION);
|
|
rowId: Integer;
|
|
displayed: String;
|
|
sUID: TUID;
|
|
pos: Integer;
|
|
header: THeader;
|
|
time: TDateTime;
|
|
body: String;
|
|
measured: Boolean;
|
|
binary: Boolean;
|
|
end;
|
|
|
|
procedure TAllHistSrchForm.FormClose(Sender: TObject; var Action: TCloseAction);
|
|
begin
|
|
updateSearchFrmXY;
|
|
if not stop2search then
|
|
begin
|
|
stop2search := True;
|
|
if Assigned(task) and not (task.Status = TTaskStatus.Canceled) then
|
|
task.Cancel;
|
|
HistPosTree.Clear;
|
|
HistPosTreeAll.Clear;
|
|
end;
|
|
if Assigned(ChatBox) then
|
|
begin
|
|
ChatBox.ClosePage;
|
|
FreeAndNil(ChatBox);
|
|
end;
|
|
AllHistSrchForm := nil;
|
|
Action := caFree;
|
|
end;
|
|
|
|
procedure TAllHistSrchForm.FormCreate(Sender: TObject);
|
|
var
|
|
bmp: TBitmap32;
|
|
i: Integer;
|
|
const
|
|
ECM_FIRST = $1500;
|
|
EM_SETCUEBANNER = ECM_FIRST + 1;
|
|
begin
|
|
targetTime := 0;
|
|
DoubleBuffered := False;
|
|
HistPosTree.NodeDataSize := SizeOf(THSItem);
|
|
HistPosTreeAll.NodeDataSize := SizeOf(THSItem);
|
|
SendMessage(SearchEdit.Handle, EM_SETCUEBANNER, WParam(True), LParam(PWideChar(WideString(GetTranslation('Text to search')))));
|
|
|
|
Randomize;
|
|
SetLength(bmps, System.CPUCount);
|
|
for i := 0 to System.CPUCount - 1 do
|
|
begin
|
|
bmp := TBitmap32.Create;
|
|
bmp.SetSize(1, 1);
|
|
bmp.Canvas.Font.Assign(Application.DefaultFont);
|
|
bmps[i] := bmp;
|
|
end;
|
|
end;
|
|
|
|
procedure TAllHistSrchForm.FormDestroy(Sender: TObject);
|
|
var
|
|
bmp: TBitmap32;
|
|
begin
|
|
for bmp in bmps do
|
|
bmp.Free;
|
|
SetLength(bmps, 0);
|
|
end;
|
|
|
|
procedure TAllHistSrchForm.FormResize(Sender: TObject);
|
|
begin
|
|
updateSearchFrmXY;
|
|
|
|
if HistPosTree.Visible and (HistPosTree.Height < 100) then
|
|
ChatBox.Height := ClientHeight - split.Height - HistPosTree.Height - pnl.Height - ChatBox.Margins.Top - ChatBox.Margins.Bottom
|
|
else if HistPosTreeAll.Visible and (HistPosTreeAll.Height < 100) then
|
|
ChatBox.Height := ClientHeight - split.Height - HistPosTreeAll.Height - pnl.Height - ChatBox.Margins.Top - ChatBox.Margins.Bottom;
|
|
end;
|
|
|
|
procedure TAllHistSrchForm.updateSearchFrmXY;
|
|
begin
|
|
if not Visible then
|
|
Exit;
|
|
if WindowState <> wsMaximized then
|
|
begin
|
|
searchfrmXY.Top := Top;
|
|
searchfrmXY.Left := Left;
|
|
searchfrmXY.Height := Height;
|
|
searchfrmXY.Width := Width;
|
|
end;
|
|
if WindowState <> wsMinimized then
|
|
searchfrmXY.maximized := WindowState = wsMaximized;
|
|
end;
|
|
|
|
procedure TAllHistSrchForm.AppEventsMessage(var Msg: tagMSG; var Handled: Boolean);
|
|
begin
|
|
if Msg.message = WM_MOUSEWHEEL then
|
|
if Msg.hwnd = HistPosTree.Handle then
|
|
HistPosTree.Perform(CM_MOUSEWHEEL, Msg.wParam, Msg.lParam)
|
|
else if Msg.hwnd = HistPosTreeAll.Handle then
|
|
HistPosTreeAll.Perform(CM_MOUSEWHEEL, Msg.wParam, Msg.lParam);
|
|
end;
|
|
|
|
procedure TAllHistSrchForm.applyFormXY;
|
|
begin
|
|
with searchfrmXY do
|
|
if Width > 0 then
|
|
begin
|
|
if maximized then
|
|
begin
|
|
SetBounds(Left, Top, Width, height);
|
|
windowState := wsMaximized;
|
|
end
|
|
else
|
|
begin
|
|
SetBounds(Left, Top, Width, height);
|
|
windowState := wsNormal
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TAllHistSrchForm.CopySelectedNodes;
|
|
var
|
|
text, multi: String;
|
|
begin
|
|
with HistPosTree.SelectedNodes.GetEnumerator do
|
|
repeat
|
|
if not MoveNext then
|
|
Break;
|
|
with PHSItem(HistPosTree.GetNodeData(Current))^ do
|
|
begin
|
|
if Length(header.prefix) > 0 then
|
|
multi := ' (' + multi + ')'
|
|
else
|
|
multi := '';
|
|
text := text + ' ' + header.date + ', ' + header.what + multi + CRLF + body + CRLF;
|
|
end;
|
|
until not Assigned(Current);
|
|
if not (text = '') then
|
|
clipboard.AsText := text.TrimRight;
|
|
end;
|
|
|
|
procedure TAllHistSrchForm.Copy1Click(Sender: TObject);
|
|
begin
|
|
CopySelectedNodes;
|
|
end;
|
|
|
|
procedure TAllHistSrchForm.FormShow(Sender: TObject);
|
|
begin
|
|
applyTaskButton(self);
|
|
theme.pic2ico(RQteFormIcon, PIC_SEARCH, icon);
|
|
stop2search := True;
|
|
thisProto := Account.AccProto;
|
|
applyFormXY;
|
|
PostMessage(Handle, WM_AFTERSHOW, 0, 0);
|
|
end;
|
|
|
|
procedure TAllHistSrchForm.FormAfterShow(var Msg: TMessage);
|
|
begin
|
|
DoAfterShow;
|
|
end;
|
|
|
|
procedure TAllHistSrchForm.DoAfterShow;
|
|
begin
|
|
radioCurrent.Checked := not all;
|
|
radioAll.Checked := all;
|
|
SwitchSource(all);
|
|
end;
|
|
|
|
procedure TAllHistSrchForm.keyEvent(Sender: TObject; var Key: Char);
|
|
begin
|
|
if Key = ^C then
|
|
ChatBox.copySel2Clpb;
|
|
end;
|
|
|
|
procedure TAllHistSrchForm.HistPosTreeAllDrawNode(Sender: TBaseVirtualTree; const PaintInfo: TVTPaintInfo);
|
|
var
|
|
s: String;
|
|
begin
|
|
PaintInfo.Canvas.Font.Assign(Application.DefaultFont);
|
|
with PHSItem(Sender.GetNodeData(PaintInfo.Node))^ do
|
|
begin
|
|
SetBkMode(PaintInfo.Canvas.Handle, TRANSPARENT);
|
|
|
|
if vsSelected in PaintInfo.Node^.States then
|
|
PaintInfo.Canvas.Font.Color := $00000000
|
|
else
|
|
PaintInfo.Canvas.Font.Color := $00333333;
|
|
|
|
case NodeType of
|
|
NT_UID:
|
|
begin
|
|
// if contactsDB.exists(Account.AccProto, hsItem.sUID) then
|
|
if thisProto.ContactExists(sUID) then
|
|
with thisProto.getContact(sUID) do
|
|
if displayed <> UID then
|
|
s := displayed + ' "' + sUID + '" (' + IntToStr(PaintInfo.Node.ChildCount) + ')'
|
|
else
|
|
s := '"' + sUID + '" (' + IntToStr(PaintInfo.Node.ChildCount) + ')';
|
|
PaintInfo.Canvas.TextOut(PaintInfo.ContentRect.Left, 3, s);
|
|
end;
|
|
NT_POSITION:
|
|
PaintInfo.canvas.textout(PaintInfo.ContentRect.Left, 3, DateTimeToStr(time));
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TAllHistSrchForm.HistPosTreeAllNodeDblClick(Sender: TBaseVirtualTree; const HitInfo: THitInfo);
|
|
begin
|
|
if HitInfo.HitNode <> nil then
|
|
with PHSItem(Sender.GetNodeData(HitInfo.HitNode))^ do
|
|
if NodeType = NT_POSITION then
|
|
begin
|
|
if thisProto.ContactExists(sUID) then
|
|
begin
|
|
contact := thisProto.getContact(sUID);
|
|
targetTime := time;
|
|
radioCurrent.Checked := True;
|
|
end;
|
|
end else
|
|
inherited;
|
|
end;
|
|
|
|
procedure TAllHistSrchForm.HistPosTreeChange(Sender: TBaseVirtualTree; Node: PVirtualNode);
|
|
begin
|
|
if Assigned(Node) then
|
|
targetTime := 0;
|
|
if HistPosTree.SelectedCount > 0 then
|
|
OpenPreview(HistPosTree.GetFirstSelected)
|
|
else
|
|
begin
|
|
ChatBox.ClearEvents;
|
|
if HistPosTree.SelectedCount = 0 then
|
|
ChatBox.ShowSearchHere;
|
|
end;
|
|
end;
|
|
|
|
procedure TAllHistSrchForm.HistPosTreeDrawNode(Sender: TBaseVirtualTree; const PaintInfo: TVTPaintInfo);
|
|
var
|
|
r: TRect;
|
|
s: String;
|
|
begin
|
|
r := PaintInfo.CellRect;
|
|
inc(r.Left, 6);
|
|
dec(r.Right, 3);
|
|
inc(r.Top, 8);
|
|
|
|
PaintInfo.Canvas.Font.Assign(Application.DefaultFont);
|
|
with PHSItem(Sender.GetNodeData(PaintInfo.Node))^ do
|
|
begin
|
|
SetBkMode(PaintInfo.Canvas.Handle, TRANSPARENT);
|
|
|
|
if NodeType = NT_HIS then
|
|
PaintInfo.Canvas.Font.Color := $00034184
|
|
else if NodeType = NT_MY then
|
|
PaintInfo.Canvas.Font.Color := $00933528;
|
|
s := header.what + ' ' + header.date;
|
|
if not (header.prefix = '') then
|
|
s := s + ' ' + header.prefix;
|
|
DrawText(PaintInfo.Canvas.Handle, s, Length(s), r, DT_WORDBREAK or DT_EXTERNALLEADING or DT_NOPREFIX);
|
|
|
|
if vsSelected in PaintInfo.Node^.States then
|
|
PaintInfo.Canvas.Font.Color := $00000000
|
|
else
|
|
PaintInfo.Canvas.Font.Color := $00333333;
|
|
if not (body = '') then
|
|
DrawText(PaintInfo.Canvas.Handle, CRLF + body, Length(CRLF + body), r, DT_WORDBREAK or DT_EXTERNALLEADING or DT_NOPREFIX);
|
|
end;
|
|
end;
|
|
|
|
procedure TAllHistSrchForm.HistPosTreeFreeNode(Sender: TBaseVirtualTree; Node: PVirtualNode);
|
|
begin
|
|
Sender.SetNodeData(Node, Default(THSItem));
|
|
end;
|
|
|
|
procedure TAllHistSrchForm.HistPosTreeKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
|
|
begin
|
|
if (Shift = [ssCtrl]) and (Key = VK_C) then
|
|
CopySelectedNodes;
|
|
end;
|
|
|
|
procedure TAllHistSrchForm.HistPosTreeMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
|
|
begin
|
|
if (Button = mbRight) and (HistPosTree.SelectedCount > 0) then
|
|
HistMenu.Popup(Mouse.CursorPos.X, Mouse.CursorPos.Y);
|
|
end;
|
|
|
|
procedure TAllHistSrchForm.HistPosTreeResize(Sender: TObject);
|
|
var
|
|
Node: PVirtualNode;
|
|
begin
|
|
if HistPosTree.Visible then
|
|
with HistPosTree do
|
|
if not (HistWidth = ClientWidth) then
|
|
begin
|
|
HistWidth := ClientWidth;
|
|
Node := GetFirst;
|
|
while Assigned(Node) do
|
|
begin
|
|
PHSItem(GetNodeData(Node))^.measured := False;
|
|
Node := GetNextSibling(Node);
|
|
end;
|
|
MeasureHeight;
|
|
end;
|
|
end;
|
|
|
|
procedure TAllHistSrchForm.HistPosTreeScroll(Sender: TBaseVirtualTree; DeltaX, DeltaY: Integer);
|
|
begin
|
|
MeasureHeight;
|
|
end;
|
|
|
|
procedure TAllHistSrchForm.OpenPreview(Node: PVirtualNode);
|
|
var
|
|
Sel: THSItem;
|
|
hev: Thevent;
|
|
Params: TParams;
|
|
MsgData: TMessageData;
|
|
begin
|
|
if not Assigned(Node) or not Visible then
|
|
Exit;
|
|
|
|
Sel := PHSItem(HistPosTree.GetNodeData(Node))^;
|
|
hev := ChatBox.GetHistory(Sel.sUID).getByRowId(Sel.rowId);
|
|
|
|
if Assigned(hev) then
|
|
with ChatBox do
|
|
begin
|
|
ClearEvents;
|
|
AddChatItem(Params, MsgData, hev, False, True);
|
|
SendChatItems(Sel.sUID, params);
|
|
ScrollToTop(False);
|
|
FreeAndNil(hev);
|
|
end;
|
|
end;
|
|
|
|
procedure TAllHistSrchForm.radioAllClick(Sender: TObject);
|
|
begin
|
|
SwitchSource(True);
|
|
end;
|
|
|
|
procedure TAllHistSrchForm.radioCurrentClick(Sender: TObject);
|
|
begin
|
|
SwitchSource(False);
|
|
end;
|
|
|
|
procedure TAllHistSrchForm.SwitchSource(srcAll: Boolean);
|
|
begin
|
|
if Assigned(contact) then
|
|
begin
|
|
radioCurrent.Caption := contact.displayed.Replace('&', '&&');
|
|
radioCurrent.Visible := True;
|
|
end
|
|
else
|
|
begin
|
|
srcAll := True;
|
|
radioCurrent.Visible := False;
|
|
end;
|
|
|
|
all := srcAll;
|
|
HistPosTreeAll.Visible := srcAll;
|
|
SchBtn.Visible := not srcAll;
|
|
SchAllBtn.Visible := srcAll;
|
|
RoasterChk.Visible := srcAll;
|
|
direction.Visible := not srcAll;
|
|
SearchEdit.SetFocus;
|
|
SearchEdit.SelStart := Length(SearchEdit.Text);
|
|
|
|
if Assigned(ChatBox) then
|
|
ChatBox.Visible := not srcAll;
|
|
|
|
if not srcAll then
|
|
LoadHistory;
|
|
end;
|
|
|
|
procedure TAllHistSrchForm.LoadHistory;
|
|
var
|
|
events: Thevents;
|
|
Node: PVirtualNode;
|
|
hsItem: PHSItem;
|
|
hist: Thistory;
|
|
begin
|
|
if Assigned(ChatBox) then
|
|
begin
|
|
hist := ChatBox.GetHistory(contact.UID2cmp);
|
|
if Assigned(hist) then
|
|
begin
|
|
ChatBox.Top := split.Top + split.Height + 1;
|
|
SelectTarget;
|
|
Exit;
|
|
end;
|
|
end;
|
|
|
|
loading.Caption := GetTranslation('Loading history...');
|
|
loading.Show;
|
|
loading.BringToFront;
|
|
AllHistSrchForm.Refresh;
|
|
|
|
if not Assigned(ChatBox) then
|
|
begin
|
|
ChatBox := TChatBox.Create(AllHistSrchForm);
|
|
with ChatBox do
|
|
begin
|
|
Hide;
|
|
Align := alBottom;
|
|
AlignWithMargins := True;
|
|
Margins.Top := 0;
|
|
Margins.Bottom := 8;
|
|
Margins.Left := 8;
|
|
Margins.Right := 8;
|
|
Constraints.MinHeight := 100;
|
|
Height := Round(AllHistSrchForm.Height / 4);
|
|
|
|
OnKeyPress := keyEvent;
|
|
Load;
|
|
InitSettings;
|
|
end;
|
|
end else
|
|
ChatBox.ClosePage;
|
|
|
|
ChatBox.OpenPage(contact, True, True);
|
|
|
|
HistPosTree.Clear;
|
|
HistPosTree.BeginUpdate;
|
|
|
|
stop2search := False;
|
|
events := ChatBox.GetHistory(contact.UID2cmp).getAllEvents;
|
|
task := TTask.Create(procedure
|
|
var
|
|
hev: Thevent;
|
|
begin
|
|
with ChatBox do
|
|
begin
|
|
if Assigned(events) then
|
|
for hev in events do
|
|
if Assigned(hev) then
|
|
begin
|
|
if stop2search or Application.Terminated then
|
|
Exit;
|
|
Node := HistPosTree.AddChild(nil);
|
|
hsItem := HistPosTree.GetNodeData(Node);
|
|
hsItem.rowId := hev.rowId;
|
|
hsItem.sUID := contact.UID;
|
|
hsItem.displayed := hev.who.displayed;
|
|
hsItem.pos := Node.Index;
|
|
hsItem.time := hev.when;
|
|
hsItem.header := hev.getHeaderTexts;
|
|
hsItem.binary := False;
|
|
if not (hev.getBodyText = '') then
|
|
hsItem.body := Trim(hev.getBodyText)
|
|
else if (Length(hev.getBodyBin) > 0) and (hev.kind = EK_msg) then
|
|
begin
|
|
hsItem.body := '[' + GetTranslation('Binary data, %u B', [Length(hev.getBodyBin)]) + ']';
|
|
hsItem.binary := True;
|
|
end else
|
|
hsItem.body := '';
|
|
hsItem.measured := False;
|
|
Include(Node.States, vsHeightMeasured);
|
|
if hev.outgoing then
|
|
hsItem.NodeType := NT_MY
|
|
else
|
|
hsItem.NodeType := NT_HIS;
|
|
hev.Free;
|
|
end;
|
|
|
|
if Assigned(events) then
|
|
SetLength(events, 0);
|
|
|
|
TThread.Synchronize(nil, procedure
|
|
begin
|
|
if stop2search or Application.Terminated then
|
|
Exit;
|
|
MeasureHeight(True);
|
|
HistPosTree.EndUpdate;
|
|
HistPosTree.Show;
|
|
Show;
|
|
Top := split.Top + split.Height + 1;
|
|
ShowSearchHere;
|
|
loading.Hide;
|
|
SelectTarget;
|
|
stop2search := True;
|
|
end);
|
|
end;
|
|
end);
|
|
task.Start;
|
|
end;
|
|
|
|
procedure TAllHistSrchForm.SelectTarget;
|
|
var
|
|
Node: PVirtualNode;
|
|
begin
|
|
if not (targetTime = 0) then
|
|
begin
|
|
HistPosTree.ClearSelection;
|
|
Node := HistPosTree.GetFirst;
|
|
while Assigned(Node) do
|
|
begin
|
|
if CompareDateTime(targetTime, PHSItem(HistPosTree.GetNodeData(Node))^.time) = 0 then
|
|
begin
|
|
HistPosTree.Selected[Node] := True;
|
|
HistPosTree.ScrollIntoView(Node, True);
|
|
OpenPreview(Node);
|
|
Break;
|
|
end else
|
|
Node := HistPosTree.GetNextSibling(Node)
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function MeasureNode(const data: PHSItem): Integer;
|
|
var
|
|
s: string;
|
|
r, r2: TRect;
|
|
bmp: TBitmap32;
|
|
i: Integer;
|
|
begin
|
|
bmp := nil;
|
|
for i := 0 to System.CPUCount - 1 do
|
|
if bmps[i].Canvas.LockCount = 0 then
|
|
begin
|
|
bmp := bmps[i];
|
|
Break;
|
|
end;
|
|
|
|
if not Assigned(bmp) then
|
|
bmp := bmps[Random(Length(bmps)-1)];
|
|
|
|
bmp.Canvas.Lock;
|
|
|
|
try
|
|
r := Rect(6, 8, HistWidth-3, 0);
|
|
with data^ do
|
|
begin
|
|
s := header.what + ' ' + header.date;
|
|
if not (header.prefix = '') then
|
|
s := s + ' ' + header.prefix;
|
|
if not (body = '') then
|
|
s := s + CRLF + body;
|
|
|
|
r2 := r;
|
|
DrawText(bmp.Canvas.Handle, s, Length(s), r2, DT_EXTERNALLEADING or DT_NOPREFIX or DT_CALCRECT);
|
|
if r2.Width > r.Width then
|
|
DrawText(bmp.Canvas.Handle, s, Length(s), r, DT_WORDBREAK or DT_EXTERNALLEADING or DT_NOPREFIX or DT_CALCRECT)
|
|
else
|
|
r := r2;
|
|
|
|
Result := r.Bottom + 9;
|
|
end;
|
|
finally
|
|
bmp.Canvas.Unlock;
|
|
end;
|
|
end;
|
|
|
|
procedure TAllHistSrchForm.MeasureHeight(doAll: Boolean = False);
|
|
var
|
|
Node, BottomNode: PVirtualNode;
|
|
Data: PHSItem;
|
|
Task: ITask;
|
|
TaskList: TList |
|
NodeHeights: TDictionary |
|
NH: TPair |
|
|
|
// Freq, StartCount, StopCount: Int64;
|
|
// TimingSeconds: Real;
|
|
|
|
procedure MeasureTask(const n: PVirtualNode; const d: PHSItem);
|
|
begin
|
|
Task := TTask.Run(procedure
|
|
var
|
|
h: Integer;
|
|
begin
|
|
h := MeasureNode(d);
|
|
d.measured := True;
|
|
MonitorEnter(NodeHeights);
|
|
try
|
|
NodeHeights.AddOrSetValue(n, h);
|
|
finally
|
|
MonitorExit(NodeHeights);
|
|
end;
|
|
end);
|
|
TaskList.Add(Task);
|
|
end;
|
|
|
|
begin
|
|
//QueryPerformanceFrequency(Freq);
|
|
//QueryPerformanceCounter(StartCount);
|
|
if doAll then
|
|
begin
|
|
Node := HistPosTree.GetFirstChild(nil);
|
|
BottomNode := nil;
|
|
end
|
|
else
|
|
begin
|
|
Node := HistPosTree.TopNode;
|
|
if Assigned(Node) and Assigned(Node.PrevSibling) then
|
|
Node := Node.PrevSibling;
|
|
// BottomNode := HistPosTree.GetNextSibling(HistPosTree.GetNodeAt(Types.Point(HistPosTree.ClientWidth - 1, HistPosTree.ClientHeight - 1)));
|
|
BottomNode := HistPosTree.BottomNode;
|
|
if Assigned(BottomNode) and Assigned(BottomNode.NextSibling) then
|
|
BottomNode := BottomNode.NextSibling;
|
|
end;
|
|
|
|
if not Assigned(Node) and not Assigned(BottomNode) then
|
|
Exit;
|
|
|
|
HistWidth := HistPosTree.ClientWidth;
|
|
TaskList := TList |
|
NodeHeights := TDictionary |
|
while Assigned(Node) do
|
|
begin
|
|
Data := PHSItem(HistPosTree.GetNodeData(Node));
|
|
|
|
if not Data.measured and Assigned(Node) and Assigned(Data) then
|
|
MeasureTask(Node, Data);
|
|
|
|
Node := HistPosTree.GetNextSibling(Node);
|
|
if Node = BottomNode then
|
|
Break;
|
|
end;
|
|
|
|
TTask.WaitForAll(TaskList.ToArray);
|
|
TaskList.Free;
|
|
|
|
for NH in NodeHeights do
|
|
HistPosTree.NodeHeight[NH.Key] := NH.Value;
|
|
NodeHeights.Free;
|
|
//QueryPerformanceCounter(StopCount);
|
|
//TimingSeconds := (StopCount - StartCount) / Freq;
|
|
//OutputDebugString(PChar(floattostr(TimingSeconds)));
|
|
end;
|
|
|
|
procedure TAllHistSrchForm.SchAllBtnClick(Sender: TObject);
|
|
var
|
|
ParentNode: PVirtualNode;
|
|
|
|
procedure addPosition(const uid: TUID; pos: Integer; time: TDateTime);
|
|
var
|
|
n: PVirtualNode;
|
|
hsItem: PHSItem;
|
|
begin
|
|
if ParentNode = nil then
|
|
begin
|
|
ParentNode := HistPosTreeAll.AddChild(nil);
|
|
hsItem := HistPosTreeAll.GetNodeData(ParentNode);
|
|
hsItem.NodeType := NT_UID;
|
|
hsItem.sUID := uid;
|
|
end;
|
|
n := HistPosTreeAll.AddChild(ParentNode);
|
|
hsItem := HistPosTreeAll.GetNodeData(n);
|
|
hsItem.NodeType := NT_POSITION;
|
|
hsItem.sUID := uid;
|
|
hsItem.pos := pos;
|
|
hsItem.time := time;
|
|
// n.CheckType := ctCheckBox;
|
|
end;
|
|
|
|
var
|
|
hist: Thistory;
|
|
i: Integer;
|
|
uid: TUID;
|
|
uids: TUIDS;
|
|
ev: Thevent;
|
|
events: Thevents;
|
|
begin
|
|
if not SchAllBtn.Visible then
|
|
Exit;
|
|
|
|
if (SearchEdit.Text = '') then
|
|
begin
|
|
SearchEdit.SetFocus;
|
|
Exit;
|
|
end;
|
|
|
|
if stop2search then
|
|
begin
|
|
stop2search := False;
|
|
SchAllBtn.Caption := getTranslation('&Stop');
|
|
HistPosTreeAll.Clear;
|
|
|
|
uids := Thistory.getExistingChats;
|
|
for uid in uids do
|
|
if not RoasterChk.Checked or (RoasterChk.Checked and Account.AccProto.readList(LT_ROSTER).exists(uid)) then
|
|
begin
|
|
hist := Thistory.Create(uid);
|
|
events := hist.dataSearch(SearchEdit.Text, caseChk.Checked);
|
|
|
|
ParentNode := nil;
|
|
i := 0;
|
|
if Length(events) > 0 then
|
|
for ev in events do
|
|
begin
|
|
if not Assigned(ev) then
|
|
Continue;
|
|
addPosition(uid, i, ev.when);
|
|
inc(i);
|
|
ev.Free;
|
|
end;
|
|
if Assigned(events) then
|
|
SetLength(events, 0);
|
|
hist.Free;
|
|
// cnt := Account.AccProto.getContact(fnUID);
|
|
end;
|
|
|
|
SchAllBtn.Caption := getTranslation('&Search');
|
|
stop2search := True;
|
|
end else
|
|
stop2search := True;
|
|
end;
|
|
|
|
procedure NoMoreMatchesDlg;
|
|
begin
|
|
MessageBox(AllHistSrchForm.Handle, PChar(GetTranslation('Nothing can be found')), PChar(GetTranslation('Search')), MB_OK);
|
|
end;
|
|
|
|
procedure TAllHistSrchForm.SchBtnClick(Sender: TObject);
|
|
var
|
|
Data: PHSItem;
|
|
Node, NextNode: PVirtualNode;
|
|
found: Boolean;
|
|
begin
|
|
if not SchBtn.Visible then
|
|
Exit;
|
|
|
|
if (SearchEdit.Text = '') then
|
|
begin
|
|
SearchEdit.SetFocus;
|
|
Exit;
|
|
end;
|
|
|
|
Node := nil;
|
|
case direction.ItemIndex of
|
|
0: Node := HistPosTree.GetFirst;
|
|
1:
|
|
begin
|
|
Node := HistPosTree.GetFirstSelected;
|
|
if Node = nil then
|
|
Node := HistPosTree.GetFirst;
|
|
end;
|
|
2:
|
|
begin
|
|
Node := HistPosTree.GetFirstSelected;
|
|
if Node = nil then
|
|
Node := HistPosTree.GetLast;
|
|
end;
|
|
3: Node := HistPosTree.GetLast;
|
|
end;
|
|
|
|
if Node = nil then
|
|
Exit;
|
|
|
|
if vsSelected in Node.States then
|
|
if direction.ItemIndex <= 1 then
|
|
Node := Node.NextSibling
|
|
else
|
|
Node := Node.PrevSibling;
|
|
|
|
found := False;
|
|
if (Node = nil) then
|
|
begin
|
|
NoMoreMatchesDlg;
|
|
SearchEdit.SetFocus;
|
|
end else
|
|
while Assigned(Node) do
|
|
begin
|
|
Data := HistPosTree.GetNodeData(Node);
|
|
|
|
if not Data.binary then
|
|
if caseChk.Checked then
|
|
found := ContainsStr(Data.body, SearchEdit.Text)
|
|
else
|
|
found := ContainsText(Data.body, SearchEdit.Text);
|
|
|
|
if found then
|
|
begin
|
|
HistPosTree.ClearSelection;
|
|
HistPosTree.Selected[Node] := True;
|
|
HistPosTree.ScrollIntoView(Node, True);
|
|
OpenPreview(Node);
|
|
|
|
if direction.ItemIndex = 0 then
|
|
direction.ItemIndex := 1
|
|
else if direction.ItemIndex = 3 then
|
|
direction.ItemIndex := 2;
|
|
direction.Refresh;
|
|
Break
|
|
end;
|
|
|
|
if direction.ItemIndex <= 1 then
|
|
NextNode := HistPosTree.GetNextSibling(Node)
|
|
else
|
|
NextNode := HistPosTree.GetPreviousSibling(Node);
|
|
|
|
if (NextNode = nil) then
|
|
begin
|
|
NoMoreMatchesDlg;
|
|
SearchEdit.SetFocus;
|
|
Break;
|
|
end else
|
|
Node := NextNode;
|
|
end;
|
|
end;
|
|
|
|
procedure TAllHistSrchForm.UpdateChatSettings;
|
|
begin
|
|
ChatBox.InitSettings;
|
|
end;
|
|
|
|
procedure TAllHistSrchForm.UpdateChatSmiles;
|
|
begin
|
|
ChatBox.UpdateSmiles;
|
|
end;
|
|
|
|
end.
|