/
AxRelease.cs
348 lines (297 loc) · 14.4 KB
/
AxRelease.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
using System;
using System.Collections.Generic;
using System.IO;
using System.Windows.Forms;
using Kofax.Eclipse.Base;
namespace Kofax.Eclipse.AxRelease
{
public class AxRelease : IReleaseScript
{
#region Standard interface to inspect the script's properties and basic settings
/// <summary>
/// This GUID is used to uniquely identify the script and distinguish it from the application.
/// Generate a GUID from Visual Studio when you first create the script and
/// keep it for the rest of its life.
/// </summary>
public Guid Id
{
get { return new Guid("{96948FB5-8E66-4548-A4BC-464FB0A9EC8D}"); }
}
/// <summary>
/// This name appears in the list of available release scripts
/// in the application's UI. The name should be localized.
/// </summary>
public string Name
{
get { return "ApplicationXtender Export"; }
}
/// <summary>
/// This description appears whenever the application decides to
/// briefly explain the script's purpose to the user. The description should also be localized.
/// </summary>
public string Description
{
get { return "Export connector for ApplicationXtender."; }
}
/// <summary>
/// The script will release batches using the mode it remembered from a previous setup.
/// </summary>
public ReleaseMode WorkingMode
{
get { return m_WorkingMode; }
}
/// <summary>
/// This simple script will process batches in both single-page and multi-page release modes.
/// </summary>
public bool IsSupported(ReleaseMode mode)
{
return true;
}
#endregion
#region Script settings - Will be remembered across sessions
/// <summary>
/// The script will release batches in this mode. The script can be configured by the setup dialog and remembered across sessions.
/// </summary>
private ReleaseMode m_WorkingMode = ReleaseMode.SinglePage;
/// <summary>
/// The destination to place the released pages. Under this destination,
/// a folder structure of "[BatchName]\[DocNumber]" will be created.
/// </summary>
private string m_Destination = string.Empty;
/// <summary>
/// ID of the user-selected file type converter to convert the released documents/pages.
/// </summary>
private Guid m_FileTypeId = Guid.Empty;
/// <summary>
/// Holds the name of the index file
/// </summary>
private string m_IndexFileName = string.Empty;
#endregion
#region Instance settings - Valid only throughout the running session
/// <summary>
/// Reference to the actively employed converter to pass the pages through
/// </summary>
private IPageOutputConverter m_PageConverter;
/// <summary>
/// Reference to the actively employed converter to pass the documents through
/// </summary>
private IDocumentOutputConverter m_DocConverter;
/// <summary>
/// Point to the destination folder for the entire released batch
/// </summary>
private string m_BatchFolder;
/// <summary>
/// Point to the destination folder for the pages to be released in the current document
/// </summary>
private string m_DocFolder;
/// <summary>
/// Dictionary to hold all file names being release
/// </summary>
IDictionary<string, string> m_FilenameReleaseData = new Dictionary<string, string>();
/// <summary>
/// Keeps track of the number of images in the batch
/// </summary>
private int m_FileCount = 1;
/// <summary>
/// Document folder name incremented every 1000 images
/// </summary>
private int m_DocFolderCount = -1;
/// <summary>
/// Variable to hold value for when a new document folder should be created
/// </summary>
private Int32 m_MaxImageFiles;
/// <summary>
/// Reference to the AX Index generator
/// </summary>
private AxIndexGenerator index;
#endregion
#region Handlers to be called during an actual release process
/// <summary>
/// This method will be called first when the release is started. The application will pass the latest information
/// from the running instance to the script through given parameters. The script should do its final check
/// for proper release conditions, throwing exceptions if problems occur.
/// </summary>
public object StartRelease(IList<IExporter> exporters, IIndexField[] indexFields, IDictionary<string, string> releaseData)
{
if (string.IsNullOrEmpty(m_Destination))
throw new Exception("Please specify a release destination");
if (string.IsNullOrEmpty(m_IndexFileName))
throw new Exception("Please specify an index file name");
m_DocConverter = null;
m_PageConverter = null;
index = new AxIndexGenerator();
foreach (IExporter exporter in exporters)
{
if (exporter.Id == m_FileTypeId)
{
if (m_WorkingMode == ReleaseMode.SinglePage)
m_PageConverter = exporter as IPageOutputConverter;
else
m_DocConverter = exporter as IDocumentOutputConverter;
}
}
/// When both of them can't be found, either the user hasn't set up properly, or the chosen converter has disappeared.
/// The script can declare that the release cannot continue or proceed with default settings.
if (m_PageConverter == null && m_DocConverter == null)
throw new Exception("Please select an output file type");
/// The application will keep any object returned from this function and pass it back to the script
/// in the EndRelease call. This is usually intended to facilitate cleanup.
return null;
}
/// <summary>
/// This method will be called after the batch has been prepared by the application
/// but before any document/page is sent to the script. The scripts usually perform
/// preparations to release the batch based on the current settings.
/// </summary>
public object StartBatch(IBatch batch)
{
m_BatchFolder = Path.Combine(m_Destination, batch.Name);
bool batchFolderCreated = !Directory.Exists(m_BatchFolder);
if (batchFolderCreated)
Directory.CreateDirectory(m_BatchFolder);
/// Again, the application will keep any object returned from this function and pass it back to the script
/// in the EndBatch call. This is usually intended to facilitate cleanup.
return batchFolderCreated;
}
/// <summary>
/// In multipage release mode, this method will be called for every document in the batch.
/// This script will simply pass documents to the selected document output converter to produce
/// the expected output files in the released batch folder.
/// </summary>
public void Release(IDocument doc)
{
CheckImageCountCreateFolder();
string outputFileName = Path.Combine(m_DocFolder, m_FileCount.ToString().PadLeft(8, '0'));
m_DocConverter.Convert(doc, Path.ChangeExtension(outputFileName, m_DocConverter.DefaultExtension));
m_FilenameReleaseData.Add("Filename" + m_FileCount, Path.ChangeExtension(outputFileName, m_DocConverter.DefaultExtension));
m_FileCount++;
index.CreateIndex(doc, m_FilenameReleaseData, Path.Combine(m_BatchFolder, m_IndexFileName));
m_FilenameReleaseData.Clear();
}
/// <summary>
/// For every document, this method will be called after it has been prepared by the application
/// but before any page is sent to the script. The scripts usually performs preparations to release
/// the document based on the current settings.
/// </summary>
public object StartDocument(IDocument doc)
{
return null;
}
/// <summary>
/// Releases single page images into folders of 1000
/// Creates a new document folder for each group of 1000 images
/// </summary>
public void Release(IPage page)
{
CheckImageCountCreateFolder();
string outputFileName = Path.Combine(m_DocFolder, m_FileCount.ToString().PadLeft(8,'0'));
m_PageConverter.Convert(page, Path.ChangeExtension(outputFileName, m_PageConverter.DefaultExtension));
m_FilenameReleaseData.Add("Filename" + m_FileCount, Path.ChangeExtension(outputFileName, m_PageConverter.DefaultExtension));
m_FileCount++;
}
/// <summary>
/// Creates the index file since we have the path to all images
/// </summary>
public void EndDocument(IDocument doc, object handle, ReleaseResult result)
{
/// The handle should always indicate whether or not the script created the document folder from scratch
if (result != ReleaseResult.Succeeded && (bool)handle)
Directory.Delete(m_DocFolder);
index.CreateIndex(doc, m_FilenameReleaseData, Path.Combine(m_BatchFolder, m_IndexFileName));
m_FilenameReleaseData.Clear();
}
/// <summary>
/// This method will be called after all documents have been sent to the script.
/// The scripts usually perform the necessary cleanup based on current settings
/// and the actual release conditions.
/// </summary>
public void EndBatch(IBatch batch, object handle, ReleaseResult result)
{
/// The handle should always indicate whether or not the script created the batch folder from scratch
if (result != ReleaseResult.Succeeded && (bool)handle)
Directory.Delete(m_BatchFolder);
}
/// <summary>
/// This method will be called after everything has been sent to the script
/// and the batch has been closed by the application. The scripts usually perform
/// necessary cleanup based on current settings and the actual release conditions.
/// </summary>
public void EndRelease(object handle, ReleaseResult result)
{
/// Since we don't do anything special in this simple script,
/// there's nothing to be cleaned up here. The handle should always be null.
}
#endregion
#region Handlers to be called during configuration requests by the user and before/after a release session
/// <summary>
/// Simply write whatever needs to persist across sessions here.
/// </summary>
public void SerializeSettings(Stream output)
{
using (BinaryWriter writer = new BinaryWriter(output))
{
writer.Write(m_Destination);
writer.Write(m_FileTypeId.ToString());
writer.Write(m_WorkingMode.ToString());
writer.Write(m_IndexFileName);
writer.Write(m_MaxImageFiles);
}
}
/// <summary>
/// Simply read whatever persisted from previous sessions here.
/// </summary>
public void DeserializeSettings(Stream input)
{
using (BinaryReader reader = new BinaryReader(input))
{
try
{
m_Destination = reader.ReadString();
m_FileTypeId = new Guid(reader.ReadString());
m_WorkingMode = (ReleaseMode)Enum.Parse(typeof(ReleaseMode), reader.ReadString());
m_IndexFileName = reader.ReadString();
//TODO: this works when the number is under 127. Need to handle large integers
m_MaxImageFiles = reader.ReadInt32();
}
catch
{
/// If the script throws exceptions here, it wouldn't be able to recover from the application.
/// This will be addressed in a later version of the API.
m_Destination = string.Empty;
m_FileTypeId = Guid.Empty;
m_WorkingMode = ReleaseMode.SinglePage;
m_IndexFileName = string.Empty;
m_MaxImageFiles = 0;
}
}
}
/// <summary>
/// Whenever the user requests to configure the script's settings, the method will be called with
/// the latest information from the application's running instance as parameters. Also, a script can
/// define and add its own information to the data table and pass it further down to the exporters.
/// </summary>
public void Setup(IList<IExporter> exporters, IIndexField[] indexFields, IDictionary<string, string> releaseData)
{
AxReleaseSetup setupDialog = new AxReleaseSetup(exporters, m_Destination,
m_FileTypeId, m_WorkingMode,
m_IndexFileName, m_MaxImageFiles);
if (setupDialog.ShowDialog() != DialogResult.OK) return;
m_Destination = setupDialog.Destination;
m_FileTypeId = setupDialog.FileTypeId;
m_WorkingMode = setupDialog.WorkingMode;
m_IndexFileName = setupDialog.IndexFileName;
m_MaxImageFiles = Int32.Parse(setupDialog.MaxImageFiles);
}
#endregion
public void CheckImageCountCreateFolder()
{
//TODO: This is a little kludgey; look at making it cleaner
if (m_FileCount % (m_MaxImageFiles - 1) == 0)
m_DocFolderCount++;
m_DocFolder = Path.Combine(m_BatchFolder, m_DocFolderCount.ToString().PadLeft(5, '0'));
//Moved this to Release(IPage) since we are only releasing single pages and allows us to keep track of the number if images
if (!Directory.Exists(m_DocFolder))
Directory.CreateDirectory(m_DocFolder);
}
}
}