Yesterday I changed the default error dialog in SMLog suite
The format of log file now is text or XML (see the new Formatting property)
Also a few minor bugs fixed (list of all graphic adapters, computer name in Windows XP etc)
Yesterday I changed the default error dialog in SMLog suite
The format of log file now is text or XML (see the new Formatting property)
Also a few minor bugs fixed (list of all graphic adapters, computer name in Windows XP etc)
Today I added the new feature for TSMExportToHTML component – the possibility to generate the html file with embedded images. Unfortunately the old IE (5/6) do not support this feature but FireFox, Opera, Safari will open the file without any problem
A few links:
http://www.sweeting.org/mark/blog/2005/07/12/base64-encoded-images-embedded-in-html
http://rifers.org/blogs/gbevin/2005/4/11/embedding_images_inside_html
Note: large images will not displayed due some limits in browser for encoded string
function GetFormattedNumber(Value: Double): string; function GetLastPos(const s: string): Integer; begin Result := Pos(DecimalSeparator, s)-1; if (Result < 1) then Result := Length(s) end; var i: Integer; begin Result := FloatToStr(Value); i := 3; while (i < GetLastPos(Result)) do begin Insert(' ', Result, GetLastPos(Result)-i+1); Inc(i, 4) end; end;
Sample to use:
lblTotal.Caption := GetFormattedNumber(123456.789);
Why I wrote this function? In Delphi I could use the FormatFloat(‘,###’, dbl) but FormatFloat uses the thousand separator which is defined in MS Windows (#160 by default). I need the space char always
In SMExport I added the new component to support the JavaScript Object Notation
The format of generated samples are available at http://www.json.org/example.html
For example:
{
“RECORD”: {
“Species No”: 90020
“Category”: “Fish”
“Common_Name”: “CommonFish 828″
“Species Name”: “Fish 275″
“Length (cm)”: 50
“Length_In”: 19,6850393700787
}
}
The dates encoded as the number of milliseconds since January 1st 1970. See the topic for this subject at
http://weblogs.asp.net/bleroy/archive/2008/01/18/dates-and-json.aspx
The binary values encoded in Base64 (same as in xml)
Added the new Actions property where developer have the control which options to enable/disable for end-user.
For example, exclude the saEditRelation flag and user could not edit the options of relation/link.
Or add the saDeleteItem flag to allow the delete the table/item in designer area
Created the new TAction for export support. Will be included in next SMExport
A few years ago Jens from OraTool.de wrote the dataengine component for cxGrid and I deployed this component as part of SMExport
But Developer Express also have the TcxTreeList and TcxDBTreeList components. In friday I wrote the dataengines for these components:
In Friday in our SIM (Shareware Information System) I added the possibility to drag’n'drop the mail content from external mailer (MS Outlook, Outlook Express etc)
To add this feature you need:
1. declare two new Cliboard formats that need to be registered:
var CF_FILECONTENTS, CF_FILEDESCRIPTOR: Integer;initialization // Initialize the OLE libraries OleInitialize(nil); // Register the clipboard formats that we need to handle in the // OLE drag drop operation CF_FILECONTENTS := RegisterClipboardFormat(CFSTR_FILECONTENTS); CF_FILEDESCRIPTOR := RegisterClipboardFormat(CFSTR_FILEDESCRIPTOR); finalization OleUninitialize;
2. in OnCreate event for your form allow window to accept drop events. Just execute the next code:
OleCheck(RegisterDragDrop(Handle, Self));
3. for your form you need implement a few methods for IDropTarget interface:
type TfrmOrderWizard = class(TForm, IDropTarget) ... private { IDropTarget } function DragEnter(const dataObj: IDataObject; grfKeyState: Longint; pt: TPoint; var dwEffect: Longint): HResult; stdcall; function DragOver(grfKeyState: Longint; pt: TPoint; var dwEffect: Longint): HResult; stdcall; function DragLeave: HResult; stdcall; function Drop(const dataObj: IDataObject; grfKeyState: Longint; pt: TPoint; var dwEffect: Longint): HResult; stdcall; { IUnknown Ignore referance counting } function _AddRef: Integer; stdcall; function _Release: Integer; stdcall; ...
where:
function TfrmOrderWizard.DragEnter(const dataObj: IDataObject; grfKeyState: Longint; pt: TPoint; var dwEffect: Longint): HResult; begin dwEffect := DROPEFFECT_COPY; Result := S_OK; end; function TfrmOrderWizard.DragOver(grfKeyState: Longint; pt: TPoint; var dwEffect: Longint): HResult; begin dwEffect := DROPEFFECT_COPY; Result := S_OK; end; function TfrmOrderWizard.DragLeave: HResult; begin Result := S_OK; end; function TfrmOrderWizard._AddRef: Integer; begin Result := 1; end; function TfrmOrderWizard._Release: Integer; begin Result := 1; end; function TfrmOrderWizard.Drop(const dataObj: IDataObject; grfKeyState: Longint; pt: TPoint; var dwEffect: Longint): HResult; const PT_TSTRING = ULONG(30); PT_UNICODE = ULONG(31); PR_BODY = PT_TSTRING or ($1000 shl 16); PR_BODY_W = PT_UNICODE or ($1000 shl 16); var aFmtEtc: TFORMATETC; aStgMed, stgmitem: TSTGMEDIUM; pData: PChar; pfgd: PFileGroupDescriptor; dwCount, dwfetch: Integer; stat: STATSTG; pstg: IStorage; pstm: IStream; begin {Make certain the data rendering is available} if (dataObj = nil) then raise Exception.Create('IDataObject-Pointer is not valid!'); with aFmtEtc do begin cfFormat := CF_TEXT; ptd := nil; dwAspect := DVASPECT_CONTENT; lindex := -1; tymed := TYMED_HGLOBAL; end; {Get the data} OleCheck(dataObj.GetData(aFmtEtc, aStgMed)); try {Lock the global memory handle to get a pointer to the data} pData := GlobalLock(aStgMed.hGlobal); { Replace Text } MemoOrder.Text := pData; finally {Finished with the pointer} GlobalUnlock(aStgMed.hGlobal); {Free the memory} ReleaseStgMedium(aStgMed); end; // Get the file descriptors with aFmtEtc do begin cfFormat := CF_FILEDESCRIPTOR; ptd := nil; dwAspect := DVASPECT_CONTENT; lindex := -1; tymed := TYMED_HGLOBAL; end; OleCheck(dataObj.GetData(aFmtEtc, aStgMed)); try pfgd := PFileGroupDescriptor(GlobalLock(aStgMed.hGlobal)); // Iterate each of the files for dwCount := 0 to pfgd.cItems-1 do begin // Set up for getting the file data with aFmtEtc do begin cfFormat := CF_FILECONTENTS; ptd := nil; dwAspect := DVASPECT_CONTENT; lindex := dwCount; tymed := TYMED_ISTORAGE; end; if (dataObj.GetData(aFmtEtc, stgmitem) = S_OK) then begin // IStorage (handle the outlook item) pstg := IStorage(stgmitem.stg); // Hard coded to open the outlook message item stream if (pstg.OpenStream('__substg1.0_1000001F', nil, STGM_SHARE_EXCLUSIVE or STGM_READ, 0, pstm) = S_OK) or (pstg.OpenStream('__substg1.0_1000001E', nil, STGM_SHARE_EXCLUSIVE or STGM_READ, 0, pstm) = S_OK) then begin pstm.Stat(stat, STATFLAG_DEFAULT); pData := AllocMem(stat.cbSize); try pstm.Read(pData, stat.cbSize, @dwFetch); // Set the msg body MemoOrder.Lines.Add(String(pData)); finally // Free buffer memory FreeMem(pData); end; // Free the stream pstm := nil; end; // Free the storage pstg := nil; // Release the storage medium ReleaseStgMedium(stgmitem); end; end; finally // Unlock the memory GlobalUnLock(aStgMed.hGlobal); // Release the storage medium ReleaseStgMedium(aStgMed); end; Result := S_OK; end;
{$IFDEF VER210} {$DEFINE SMForDelphi3} {$DEFINE SMForDelphi4} {$DEFINE SMForDelphi5} {$DEFINE SMForDelphi6} {$DEFINE SMForDelphi7} {$DEFINE SMForDelphi2005} {$DEFINE SMForDelphi2006} {$IFDEF BCB} {$DEFINE SMForBCB2006} {$DEFINE SMForBCB2007} {$DEFINE SMForBCB2009} {$DEFINE SMForBCB2010} {$ENDIF} {$DEFINE SMForDelphi2007} {$DEFINE SMForRADStudio2007} {$DEFINE SMForDelphi2009} {$DEFINE SMForDelphi2010} {$ENDIF}
{returns an integer value (0 to 100) rating the key quality}
function PasswordQuality(const strPassword: string): Integer;
var
i, j, intLen: Integer;
QC: Double;
boolUpper, boolLower: Boolean;
begin
Result := 0;
intLen := Length(strPassword);
QC := 4*intLen;
{at least 5 characters in password required}
if (intLen > 4) then
begin
{check for repetitions (abcabc, aaaaa, 121212, etc}
for i := 1 to (intLen div 2) do
begin
j := i+1;
while (j <= intLen ) do
begin
if (Copy(strPassword, 1, i) = Copy(strPassword, j, i)) then exit;
Inc(j, i);
end
end;
{check the upper/lower cases}
boolUpper := False;
boolLower := False;
for i := 1 to intLen do
begin
if (strPassword[i] in ['A'..'Z']) then
boolUpper := True;
if (strPassword[i] in ['a'..'z']) then
boolLower := True;
end;
if boolUpper and boolLower then
QC := 1.5*QC;
{check the numbers}
for i := 1 to intLen do
begin
if (strPassword[i] in ['0'..'9']) then
if (boolUpper or boolLower) then
QC := 1.5*QC;
end;
{check the signs}
for i := 1 to intLen do
begin
if (strPassword[i] < ’0′) or (strPassword[i] > ‘z’) or
((strPassword[i] > ’9′) and (strPassword[i] < ‘A’)) then
QC := 1.5*QC;
end;
if (QC > 100) then
QC := 100;
Result := Trunc(QC);
end;
end;
Sample to use:
i := PasswordQuality(edPassword.Text);
lblPWQuality.Caption := IntToStr(i);
if (i < 30) then
lblPWQuality.Font.Color := clRed
else
if (i < 60) then
lblPWQuality.Font.Color := clYellow
else
lblPWQuality.Font.Color := clWindowText;