Hyperlink.cs 13 KB

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