Hyperlink.cs 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354
  1. using System;
  2. using System.ComponentModel;
  3. using System.IO;
  4. using FastReport.Utils;
  5. using FastReport.Data;
  6. using System.Drawing.Design;
  7. using System.Text.RegularExpressions;
  8. namespace FastReport
  9. {
  10. /// <summary>
  11. /// Specifies the hyperlink type.
  12. /// </summary>
  13. public enum HyperlinkKind
  14. {
  15. /// <summary>
  16. /// Specifies the hyperlink to external URL such as "http://www.fast-report.com", "mailto:"
  17. /// or any other system command.
  18. /// </summary>
  19. URL,
  20. /// <summary>
  21. /// Specifies hyperlink to a given page number.
  22. /// </summary>
  23. PageNumber,
  24. /// <summary>
  25. /// Specifies hyperlink to a bookmark.
  26. /// </summary>
  27. Bookmark,
  28. /// <summary>
  29. /// Specifies hyperlink to external report. This report will be run when you follow the hyperlink.
  30. /// </summary>
  31. DetailReport,
  32. /// <summary>
  33. /// Specifies hyperlink to this report's page. The page will be run when you follow the hyperlink.
  34. /// </summary>
  35. DetailPage,
  36. /// <summary>
  37. /// Specifies a custom hyperlink. No actions performed when you click it, you should handle it
  38. /// in the object's Click event handler.
  39. /// </summary>
  40. Custom
  41. }
  42. /// <summary>
  43. /// This class contains a hyperlink settings.
  44. /// </summary>
  45. [TypeConverter(typeof(FastReport.TypeConverters.FRExpandableObjectConverter))]
  46. public class Hyperlink
  47. {
  48. #region Fields
  49. private ReportComponentBase parent;
  50. private HyperlinkKind kind;
  51. private string expression;
  52. private string value;
  53. private string detailReportName;
  54. private string detailPageName;
  55. private string reportParameter;
  56. private string valuesSeparator;
  57. private string saveValue;
  58. private bool openLinkInNewTab;
  59. #endregion
  60. #region Properties
  61. /// <summary>
  62. /// Gets or sets the kind of hyperlink.
  63. /// </summary>
  64. /// <remarks>
  65. /// <para>Use the <b>Kind</b> property to define hyperlink's behavior.
  66. /// The hyperlink may be used to navigate to the external url, the page number,
  67. /// the bookmark defined by other report object, the external report, the other page of this report,
  68. /// and custom hyperlink.</para>
  69. /// </remarks>
  70. [DefaultValue(HyperlinkKind.URL)]
  71. public HyperlinkKind Kind
  72. {
  73. get { return kind; }
  74. set { kind = value; }
  75. }
  76. /// <summary>
  77. /// Gets or sets the expression which value will be used for navigation.
  78. /// </summary>
  79. /// <remarks>
  80. /// <para>Normally you should set the <b>Expression</b> property to
  81. /// any valid expression that will be calculated when this object is about to print.
  82. /// The value of an expression will be used for navigation.</para>
  83. /// <para>If you want to navigate to some fixed data (URL or page number, for example),
  84. /// use the <see cref="Value"/> property instead.</para>
  85. /// </remarks>
  86. [Editor("FastReport.TypeEditors.HyperlinkExpressionEditor, FastReport", typeof(UITypeEditor))]
  87. public string Expression
  88. {
  89. get { return expression; }
  90. set { expression = value; }
  91. }
  92. /// <summary>
  93. /// Gets or sets a value that will be used for navigation.
  94. /// </summary>
  95. /// <remarks>
  96. /// Use this property to specify the fixed data (such as URL, page number etc). If you want to
  97. /// navigate to some dynamically calculated value, use the <see cref="Expression"/> property instead.
  98. /// </remarks>
  99. public string Value
  100. {
  101. get { return value; }
  102. set
  103. {
  104. if (!Regex.IsMatch(value, "(javascript)|(<\\s*script\\s*>)", RegexOptions.IgnoreCase))
  105. {
  106. this.value = value;
  107. }
  108. else
  109. {
  110. this.value = "";
  111. }
  112. }
  113. }
  114. /// <summary>
  115. /// Gets or sets a value that indicate should be links open in new tab or not.
  116. /// </summary>
  117. /// <remarks>
  118. /// It works for HTML-export only!
  119. /// </remarks>
  120. public bool OpenLinkInNewTab
  121. {
  122. get { return openLinkInNewTab; }
  123. set { openLinkInNewTab = value; }
  124. }
  125. /// <summary>
  126. /// Gets or sets an external report file name.
  127. /// </summary>
  128. /// <remarks>
  129. /// <para>Use this property if <see cref="Kind"/> is set to <b>DetailReport</b>. </para>
  130. /// <para>When you follow the hyperlink, this report will be loaded and run.
  131. /// You also may specify the report's parameter in the <see cref="ReportParameter"/> property.</para>
  132. /// </remarks>
  133. [Editor("FastReport.TypeEditors.HyperlinkReportFileEditor, FastReport", typeof(UITypeEditor))]
  134. public string DetailReportName
  135. {
  136. get { return detailReportName; }
  137. set { detailReportName = value; }
  138. }
  139. /// <summary>
  140. /// Gets or sets the name of this report's page.
  141. /// </summary>
  142. /// <remarks>
  143. /// <para>Use this property if <see cref="Kind"/> is set to <b>DetailPage</b>. </para>
  144. /// <para>When you follow the hyperlink, the specified page will be executed. It may contain the
  145. /// detailed report. You also may specify the report's parameter in the
  146. /// <see cref="ReportParameter"/> property.</para>
  147. /// </remarks>
  148. [Editor("FastReport.TypeEditors.HyperlinkReportPageEditor, FastReport", typeof(UITypeEditor))]
  149. public string DetailPageName
  150. {
  151. get { return detailPageName; }
  152. set { detailPageName = value; }
  153. }
  154. /// <summary>
  155. /// Gets or sets a parameter's name that will be set to hyperlink's value.
  156. /// </summary>
  157. /// <remarks>
  158. /// Use this property if <see cref="Kind"/> is set to <b>DetailReport</b> or <b>DetailPage</b>.
  159. /// <para>If you want to pass the hyperlink's value to the report's parameter, specify the
  160. /// parameter name in this property. This parameter will be set to the hyperlink's value
  161. /// before running a report. It may be used to display detailed information about clicked item.</para>
  162. /// <para>It is also possible to pass multiple values to several parameters. If hyperlink's value
  163. /// contains separators (the separator string can be set in the <see cref="ValuesSeparator"/>
  164. /// property), it will be splitted to several values. That values will be passed to nested parameters
  165. /// of the <b>ReportParameter</b> (you should create nested parameters by youself). For example, you have
  166. /// the <b>ReportParameter</b> called "SelectedValue" which has two nested parameters: the first one is
  167. /// "Employee" and the second is "Category". The hyperlink's value is "Andrew Fuller;Beverages".
  168. /// It will be splitted to two values: "Andrew Fuller" and "Beverages". The first nested parameter
  169. /// of the <b>ReportParameter</b> that is "Employee" in our case will be set to "Andrew Fuller";
  170. /// the second nested parameter ("Category") will be set to "Beverages".</para>
  171. /// <para>Note: when you create a parameter in the detailed report, don't forget to set
  172. /// its <b>DataType</b> property. It is used to convert string values to actual data type.
  173. /// </para>
  174. /// </remarks>
  175. [Editor("FastReport.TypeEditors.HyperlinkReportParameterEditor, FastReport", typeof(UITypeEditor))]
  176. public string ReportParameter
  177. {
  178. get { return reportParameter; }
  179. set { reportParameter = value; }
  180. }
  181. /// <summary>
  182. /// Gets or sets a string that will be used as a separator to pass several values
  183. /// to the external report parameters.
  184. /// </summary>
  185. public string ValuesSeparator
  186. {
  187. get { return valuesSeparator; }
  188. set { valuesSeparator = value; }
  189. }
  190. internal ReportComponentBase Parent
  191. {
  192. get { return parent; }
  193. }
  194. internal Report Report
  195. {
  196. get { return parent.Report; }
  197. }
  198. #endregion
  199. #region Private Methods
  200. private bool ShouldSerializeValuesSeparator()
  201. {
  202. return ValuesSeparator != ";";
  203. }
  204. #endregion
  205. #region Public Methods
  206. /// <summary>
  207. /// Assigns values from another source.
  208. /// </summary>
  209. /// <param name="source">Source to assign from.</param>
  210. public void Assign(Hyperlink source)
  211. {
  212. Kind = source.Kind;
  213. Expression = source.Expression;
  214. Value = source.Value;
  215. DetailReportName = source.DetailReportName;
  216. ReportParameter = source.ReportParameter;
  217. DetailPageName = source.DetailPageName;
  218. OpenLinkInNewTab = source.openLinkInNewTab;
  219. }
  220. internal bool Equals(Hyperlink h)
  221. {
  222. return h != null && Kind == h.Kind && Expression == h.Expression &&
  223. DetailReportName == h.DetailReportName && ReportParameter == h.ReportParameter &&
  224. DetailPageName == h.DetailPageName;
  225. }
  226. internal void SetParent(ReportComponentBase parent)
  227. {
  228. this.parent = parent;
  229. }
  230. internal void Calculate()
  231. {
  232. if (!String.IsNullOrEmpty(Expression))
  233. {
  234. object value = Report.Calc(Expression);
  235. Value = value == null ? "" : value.ToString();
  236. }
  237. }
  238. internal Report GetReport(bool updateParameter)
  239. {
  240. Report report = Report.FromFile(DetailReportName);
  241. Report.Dictionary.ReRegisterData(report.Dictionary);
  242. if (updateParameter)
  243. SetParameters(report);
  244. return report;
  245. }
  246. internal void SetParameters(Report report)
  247. {
  248. if (!String.IsNullOrEmpty(ReportParameter))
  249. {
  250. Parameter param = report.GetParameter(ReportParameter);
  251. if (param != null)
  252. {
  253. if (Value.IndexOf(ValuesSeparator) != -1)
  254. {
  255. string[] values = Value.Split(new string[] { ValuesSeparator }, StringSplitOptions.RemoveEmptyEntries);
  256. for (int i = 0; i < values.Length; i++)
  257. {
  258. if (i < param.Parameters.Count)
  259. param.Parameters[i].AsString = values[i];
  260. }
  261. }
  262. else
  263. {
  264. param.AsString = Value;
  265. }
  266. }
  267. }
  268. }
  269. internal void Serialize(FRWriter writer, Hyperlink hyperlink)
  270. {
  271. if (Kind != hyperlink.Kind)
  272. writer.WriteValue("Hyperlink.Kind", Kind);
  273. if (Expression != hyperlink.Expression)
  274. writer.WriteStr("Hyperlink.Expression", Expression);
  275. if (Value != hyperlink.Value)
  276. writer.WriteStr("Hyperlink.Value", Value);
  277. if (DetailReportName != hyperlink.DetailReportName)
  278. {
  279. // when saving to the report file, convert absolute path to the external report to relative path
  280. // (based on the main report path).
  281. string value = DetailReportName;
  282. if (writer.SerializeTo == SerializeTo.Report && Report != null && !String.IsNullOrEmpty(Report.FileName))
  283. value = FileUtils.GetRelativePath(DetailReportName, Path.GetDirectoryName(Report.FileName));
  284. writer.WriteStr("Hyperlink.DetailReportName", value);
  285. }
  286. if (DetailPageName != hyperlink.DetailPageName)
  287. writer.WriteStr("Hyperlink.DetailPageName", DetailPageName);
  288. if (ReportParameter != hyperlink.ReportParameter)
  289. writer.WriteStr("Hyperlink.ReportParameter", ReportParameter);
  290. if (ValuesSeparator != hyperlink.ValuesSeparator)
  291. writer.WriteStr("Hyperlink.ValuesSeparator", ValuesSeparator);
  292. if (OpenLinkInNewTab != hyperlink.OpenLinkInNewTab)
  293. writer.WriteBool("Hyperlink.OpenLinkInNewTab", OpenLinkInNewTab);
  294. }
  295. internal void OnAfterLoad()
  296. {
  297. // convert relative path to the external report to absolute path (based on the main report path).
  298. if (String.IsNullOrEmpty(DetailReportName) || String.IsNullOrEmpty(Report.FileName))
  299. return;
  300. if (!Path.IsPathRooted(DetailReportName))
  301. DetailReportName = Path.GetDirectoryName(Report.FileName) + Path.DirectorySeparatorChar + DetailReportName;
  302. }
  303. internal void SaveState()
  304. {
  305. saveValue = Value;
  306. }
  307. internal void RestoreState()
  308. {
  309. Value = saveValue;
  310. }
  311. #endregion
  312. internal Hyperlink(ReportComponentBase parent)
  313. {
  314. SetParent(parent);
  315. expression = "";
  316. value = "";
  317. detailReportName = "";
  318. detailPageName = "";
  319. reportParameter = "";
  320. valuesSeparator = ";";
  321. }
  322. }
  323. }