PageRenderTime 55ms CodeModel.GetById 11ms RepoModel.GetById 0ms app.codeStats 0ms

/vendor/jvcl/run/JvDBImage.pas

http://my-chuanqi.googlecode.com/
Pascal | 500 lines | 392 code | 39 blank | 69 comment | 46 complexity | 5c82fb4c4041ef6566fd9607a790eec9 MD5 | raw file
  1. {-----------------------------------------------------------------------------
  2. The contents of this file are subject to the Mozilla Public License
  3. Version 1.1 (the "License"); you may not use this file except in compliance
  4. with the License. You may obtain a copy of the License at
  5. http://www.mozilla.org/MPL/MPL-1.1.html
  6. Software distributed under the License is distributed on an "AS IS" basis,
  7. WITHOUT WARRANTY OF ANY KIND, either expressed or implied. See the License for
  8. the specific language governing rights and limitations under the License.
  9. The Original Code is: JvDBImage.PAS, released on 2004-04-09.
  10. The Initial Developers of the Original Code is
  11. Sergio Samayoa <sergiosamayoa att icon dott com dott gt> and Peter Thornqvist <peter att users dott sourceforge dott net>
  12. Portions created by Sergio Samayoa are Copyright (C) 2004 Sergio Samayoa.
  13. Portions created by Peter Thornqvist are Copyright (C) 2004 Peter Thornqvist.
  14. All Rights Reserved.
  15. Contributor(s):
  16. You may retrieve the latest version of this file at the Project JEDI's JVCL home page,
  17. located at http://jvcl.sourceforge.net
  18. Known Issues:
  19. -----------------------------------------------------------------------------}
  20. // $Id: JvDBImage.pas 11362 2007-06-21 06:59:12Z marquardt $
  21. {
  22. Documentation:
  23. *************
  24. WHAT IT IS:
  25. This component is a TDBImage replacement that supports other image
  26. formats than bitmap, a limitation of TDBImage since D1.
  27. IMAGE FORMATS:
  28. See JvGraphics.pas for details
  29. SUPPORT FOR TDBCtrlGrid:
  30. You can safely put an TJvDBImage in TDBCtrlGrid.
  31. }
  32. unit JvDBImage;
  33. {$I jvcl.inc}
  34. interface
  35. uses
  36. {$IFDEF UNITVERSIONING}
  37. JclUnitVersioning,
  38. {$ENDIF UNITVERSIONING}
  39. Windows, Messages, Classes, Graphics, Controls,
  40. Clipbrd, DB, DBCtrls, Forms, Contnrs,
  41. JvJVCLUtils;
  42. type
  43. TJvDBImage = class(TDBImage)
  44. private
  45. FAutoDisplay: Boolean;
  46. FDataLink: TFieldDataLink;
  47. FOldPictureChange: TNotifyEvent;
  48. FPictureLoaded: Boolean;
  49. FProportional: Boolean;
  50. FOnGetGraphicClass: TJvGetGraphicClassEvent;
  51. FTransparent: Boolean;
  52. procedure SetAutoDisplay(Value: Boolean);
  53. procedure SetProportional(Value: Boolean);
  54. procedure DataChange(Sender: TObject);
  55. procedure PictureChanged(Sender: TObject);
  56. procedure UpdateData(Sender: TObject);
  57. procedure SetTransparent(const Value: Boolean);
  58. protected
  59. procedure CreateHandle; override;
  60. procedure CheckFieldType;
  61. procedure AssignGraphicTo(Picture: TPicture);
  62. function DestRect(W, H, CW, CH: Integer): TRect;
  63. procedure Paint; override;
  64. procedure WMLButtonDblClk(var Msg: TWMLButtonDblClk); message WM_LBUTTONDBLCLK;
  65. procedure WMPaste(var Msg: TWMPaste); message WM_PASTE;
  66. procedure KeyPress(var Key: Char); override;
  67. function CanAutoSize(var NewWidth, NewHeight: Integer): Boolean; override;
  68. public
  69. constructor Create(AOwner: TComponent); override;
  70. procedure LoadPicture;
  71. procedure PasteFromClipboard;
  72. published
  73. property AutoSize;
  74. property AutoDisplay: Boolean read FAutoDisplay write SetAutoDisplay default True;
  75. {$IFDEF COMPILER6_UP}
  76. property BevelEdges;
  77. property BevelInner;
  78. property BevelKind default bkNone;
  79. property BevelOuter;
  80. {$ENDIF COMPILER6_UP}
  81. property Proportional: Boolean read FProportional write SetProportional default False;
  82. property Transparent: Boolean read FTransparent write SetTransparent default False;
  83. property OnGetGraphicClass: TJvGetGraphicClassEvent read FOnGetGraphicClass write FOnGetGraphicClass;
  84. end;
  85. {$IFDEF UNITVERSIONING}
  86. const
  87. UnitVersioning: TUnitVersionInfo = (
  88. RCSfile: '$URL: https://jvcl.svn.sourceforge.net:443/svnroot/jvcl/trunk/jvcl/run/JvDBImage.pas $';
  89. Revision: '$Revision: 11362 $';
  90. Date: '$Date: 2007-06-20 23:59:12 -0700 (Wed, 20 Jun 2007) $';
  91. LogPath: 'JVCL\run'
  92. );
  93. {$ENDIF UNITVERSIONING}
  94. implementation
  95. uses
  96. DBConsts, SysUtils,
  97. JvConsts;
  98. //=== { TJvDBImage } =========================================================
  99. constructor TJvDBImage.Create(AOwner: TComponent);
  100. begin
  101. inherited Create(AOwner);
  102. // we cannot use the inherited AutoDisplay - it raises an "Invalid Bitmap" if
  103. // the first record in a table is an image type not supported by TDBImage
  104. inherited AutoDisplay := False;
  105. FAutoDisplay := True;
  106. FOldPictureChange := Picture.OnChange;
  107. Picture.OnChange := PictureChanged;
  108. end;
  109. procedure TJvDBImage.SetProportional(Value: Boolean);
  110. begin
  111. if FProportional <> Value then
  112. begin
  113. FProportional := Value;
  114. Invalidate;
  115. end;
  116. end;
  117. procedure TJvDBImage.CheckFieldType;
  118. begin
  119. if Field = nil then
  120. Exit;
  121. with Field do
  122. if not IsBlob then
  123. DatabaseErrorFmt(SFieldTypeMismatch, [DisplayName, FieldTypeNames[ftBlob], FieldTypeNames[DataType]]);
  124. end;
  125. procedure TJvDBImage.CreateHandle;
  126. begin
  127. inherited CreateHandle;
  128. if FDataLink = nil then
  129. begin
  130. // (p3) get a pointer to the datalink (it is private in TDBImage):
  131. FDataLink := TFieldDataLink(SendMessage(Handle, CM_GETDATALINK, 0, 0));
  132. if FDataLink <> nil then
  133. begin
  134. FDataLink.OnDataChange := DataChange;
  135. FDataLink.OnUpdateData := UpdateData;
  136. // (p3) it is now safe to call LoadPicture because we have control over the datalink:
  137. if FAutoDisplay then
  138. LoadPicture
  139. else
  140. Invalidate;
  141. end;
  142. end;
  143. end;
  144. procedure TJvDBImage.AssignGraphicTo(Picture: TPicture);
  145. var
  146. Graphic: TGraphic;
  147. GraphicClass: TGraphicClass;
  148. Stream: TMemoryStream;
  149. begin
  150. // If nil field or null field just exit
  151. if (Field = nil) or Field.IsNull then
  152. Exit;
  153. CheckFieldType;
  154. GraphicClass := nil;
  155. Stream := TMemoryStream.Create;
  156. try
  157. // Move blob data to Stream
  158. TBlobField(Field).SaveToStream(Stream);
  159. // Figure out which Graphic class is...
  160. GraphicClass := GetGraphicClass(Stream);
  161. // Call user event
  162. if Assigned(FOnGetGraphicClass) then
  163. FOnGetGraphicClass(Self, Stream, GraphicClass);
  164. // If we got one, load it..
  165. if GraphicClass <> nil then
  166. begin
  167. Graphic := GraphicClass.Create;
  168. try
  169. Stream.Position := 0;
  170. Graphic.LoadFromStream(Stream);
  171. Picture.Graphic := Graphic;
  172. finally
  173. Graphic.Free;
  174. end;
  175. end
  176. else // try the old fashioned way
  177. Picture.Assign(Field);
  178. finally
  179. Stream.Free;
  180. end;
  181. end;
  182. procedure TJvDBImage.PictureChanged(Sender: TObject);
  183. begin
  184. if AutoSize and (Picture.Width > 0) and (Picture.Height > 0) then
  185. SetBounds(Left, Top, Picture.Width, Picture.Height);
  186. FOldPictureChange(Sender);
  187. FPictureLoaded := Picture.Graphic <> nil;
  188. end;
  189. procedure TJvDBImage.DataChange(Sender: TObject);
  190. begin
  191. Picture.Graphic := nil;
  192. FPictureLoaded := False;
  193. if FAutoDisplay then
  194. LoadPicture;
  195. end;
  196. function TJvDBImage.DestRect(W, H, CW, CH: Integer): TRect;
  197. var
  198. XYAspect: Double;
  199. begin
  200. if AutoSize then
  201. begin
  202. Result := ClientRect;
  203. Exit;
  204. end;
  205. if Stretch or (Proportional and ((W > CW) or (H > CH))) then
  206. begin
  207. if Proportional and (W > 0) and (H > 0) then
  208. begin
  209. XYAspect := W / H;
  210. if W > H then
  211. begin
  212. W := CW;
  213. H := Trunc(CW / XYAspect);
  214. if H > CH then // woops, too big
  215. begin
  216. H := CH;
  217. W := Trunc(CH * XYAspect);
  218. end;
  219. end
  220. else
  221. begin
  222. H := CH;
  223. W := Trunc(CH * XYAspect);
  224. if W > CW then // woops, too big
  225. begin
  226. W := CW;
  227. H := Trunc(CW / XYAspect);
  228. end;
  229. end;
  230. end
  231. else
  232. begin
  233. W := CW;
  234. H := CH;
  235. end;
  236. end;
  237. with Result do
  238. begin
  239. Left := 0;
  240. Top := 0;
  241. Right := W;
  242. Bottom := H;
  243. end;
  244. if Center then
  245. OffsetRect(Result, (CW - W) div 2, (CH - H) div 2);
  246. end;
  247. procedure TJvDBImage.Paint;
  248. var
  249. Size: TSize;
  250. R: TRect;
  251. S: string;
  252. DrawPict: TPicture;
  253. Form: TCustomForm;
  254. Pal: HPalette;
  255. begin
  256. with Canvas do
  257. begin
  258. Brush.Style := bsSolid;
  259. Brush.Color := Color;
  260. if FPictureLoaded or (csPaintCopy in ControlState) and Assigned(FDataLink) then
  261. begin
  262. DrawPict := TPicture.Create;
  263. Pal := 0;
  264. try
  265. if (csPaintCopy in ControlState) and Assigned(FDataLink.Field) and
  266. FDataLink.Field.IsBlob then
  267. begin
  268. AssignGraphicTo(DrawPict);
  269. if DrawPict.Graphic is TBitmap then
  270. DrawPict.Bitmap.IgnorePalette := QuickDraw;
  271. end
  272. else
  273. begin
  274. DrawPict.Assign(Picture);
  275. if Focused and (DrawPict.Graphic <> nil) and
  276. (DrawPict.Graphic.Palette <> 0) then
  277. begin
  278. Pal := SelectPalette(Handle, DrawPict.Graphic.Palette, False);
  279. RealizePalette(Handle);
  280. end;
  281. end;
  282. FillRect(ClientRect); // (p3) always fill or the text might be visible through the control
  283. if (DrawPict.Graphic <> nil) and not DrawPict.Graphic.Empty then
  284. begin
  285. DrawPict.Graphic.Transparent := Self.Transparent;
  286. // (p3) DestRect adjusts the rect according to the values of Stretch, Center and Proportional
  287. R := DestRect(DrawPict.Width, DrawPict.Height, Self.Width, Self.Height);
  288. StretchDraw(R, DrawPict.Graphic);
  289. ExcludeClipRect(Handle, R.Left, R.Top, R.Right, R.Bottom);
  290. FillRect(ClientRect);
  291. SelectClipRgn(Handle, 0);
  292. end;
  293. finally
  294. if Pal <> 0 then
  295. SelectPalette(Handle, Pal, True);
  296. DrawPict.Free;
  297. end;
  298. end
  299. else
  300. begin
  301. Font := Self.Font;
  302. if (FDataLink <> nil) and (FDataLink.Field <> nil) then
  303. S := FDataLink.Field.DisplayLabel
  304. else
  305. S := Name;
  306. if S = '' then
  307. S := Self.ClassName;
  308. S := '(' + S + ')';
  309. Size := TextExtent(S);
  310. R := ClientRect;
  311. TextRect(R, (R.Right - Size.cx) div 2, (R.Bottom - Size.cy) div 2, S);
  312. end;
  313. Form := GetParentForm(Self);
  314. if (Form <> nil) and (Form.ActiveControl = Self) and not
  315. (csDesigning in ComponentState) and not (csPaintCopy in ControlState) then
  316. begin
  317. Brush.Color := clWindowFrame;
  318. FrameRect(ClientRect);
  319. end;
  320. end;
  321. end;
  322. procedure TJvDBImage.LoadPicture;
  323. begin
  324. if not FPictureLoaded then
  325. try
  326. AssignGraphicTo(Picture);
  327. except
  328. Picture.Graphic := nil;
  329. raise;
  330. end;
  331. end;
  332. procedure TJvDBImage.UpdateData(Sender: TObject);
  333. var
  334. Stream: TMemoryStream;
  335. begin
  336. CheckFieldType;
  337. // If there is no graphic just clear field and exit
  338. if Picture.Graphic = nil then
  339. begin
  340. Field.Clear;
  341. Exit;
  342. end;
  343. Stream := TMemoryStream.Create;
  344. try
  345. Picture.Graphic.SaveToStream(Stream);
  346. Stream.Position := 0;
  347. TBlobField(Field).LoadFromStream(Stream);
  348. finally
  349. Stream.Free;
  350. end;
  351. end;
  352. procedure TJvDBImage.SetAutoDisplay(Value: Boolean);
  353. begin
  354. if FAutoDisplay <> Value then
  355. begin
  356. FAutoDisplay := Value;
  357. if Value then
  358. LoadPicture;
  359. end;
  360. end;
  361. procedure TJvDBImage.PasteFromClipboard;
  362. begin
  363. if FDataLink.Edit then
  364. begin
  365. if Clipboard.HasFormat(CF_BITMAP) then
  366. Picture.Bitmap.Assign(Clipboard)
  367. else
  368. if Clipboard.HasFormat(CF_METAFILEPICT) or
  369. Clipboard.HasFormat(CF_ENHMETAFILE) then
  370. Picture.Metafile.Assign(Clipboard)
  371. else
  372. if Clipboard.HasFormat(CF_PICTURE) then
  373. Picture.Assign(Clipboard);
  374. end;
  375. end;
  376. function ControlCursorPos(Control: TControl): TPoint;
  377. begin
  378. GetCursorPos(Result);
  379. Result := Control.ScreenToClient(Result);
  380. end;
  381. procedure TJvDBImage.WMLButtonDblClk(var Msg: TWMLButtonDblClk);
  382. begin
  383. // we can't call inherited because TDBImage loads the image there as well
  384. // and will get mighty upset if it's not a BMP, so we have to redo the
  385. // code in TControl as closely as we can
  386. SendCancelMode(Self);
  387. // inherited;
  388. if csCaptureMouse in ControlStyle then
  389. MouseCapture := True;
  390. if csClickEvents in ControlStyle then
  391. DblClick;
  392. if not (csNoStdEvents in ControlStyle) then
  393. with Msg do
  394. if (Width > 32768) or (Height > 32768) then
  395. with ControlCursorPos(Self) do
  396. MouseDown(mbLeft, KeysToShiftState(Keys), X, Y)
  397. else
  398. MouseDown(mbLeft, KeysToShiftState(Keys), XPos, YPos);
  399. LoadPicture;
  400. end;
  401. procedure TJvDBImage.KeyPress(var Key: Char);
  402. begin
  403. case Key of
  404. CtrlC:
  405. CopyToClipboard;
  406. CtrlV:
  407. PasteFromClipboard;
  408. CtrlX:
  409. CutToClipboard;
  410. Cr:
  411. LoadPicture;
  412. Esc:
  413. if FDataLink <> nil then
  414. FDataLink.Reset;
  415. else // this should be safe, TDBImage doesn't handle any other keys
  416. inherited KeyPress(Key);
  417. end;
  418. end;
  419. procedure TJvDBImage.WMPaste(var Msg: TWMPaste);
  420. begin
  421. PasteFromClipboard;
  422. end;
  423. procedure TJvDBImage.SetTransparent(const Value: Boolean);
  424. begin
  425. if FTransparent <> Value then
  426. begin
  427. FTransparent := Value;
  428. Invalidate;
  429. end;
  430. end;
  431. function TJvDBImage.CanAutoSize(var NewWidth, NewHeight: Integer): Boolean;
  432. begin
  433. Result := True;
  434. if not (csDesigning in ComponentState) or (Picture.Width > 0) and (Picture.Height > 0) then
  435. begin
  436. if Align in [alNone, alLeft, alRight] then
  437. NewWidth := Picture.Width + Ord(BorderStyle = bsSingle) * 4;
  438. if Align in [alNone, alTop, alBottom] then
  439. NewHeight := Picture.Height + Ord(BorderStyle = bsSingle) * 4;
  440. end;
  441. end;
  442. initialization
  443. {$IFDEF UNITVERSIONING}
  444. RegisterUnitVersion(HInstance, UnitVersioning);
  445. {$ENDIF UNITVERSIONING}
  446. { registration happens in GraphicSignatures Needed() }
  447. finalization
  448. {$IFDEF UNITVERSIONING}
  449. UnregisterUnitVersion(HInstance);
  450. {$ENDIF UNITVERSIONING}
  451. end.