Simple Document Management Using VFP, Part 1 Russell Campbell russcampbell@interthink.com



Similar documents
Search help. More on Office.com: images templates

Introduction to Open Atrium s workflow

My Secure Backup: How to reduce your backup size

After you install Spark, you'll get going by logging in and adding contacts. Try out a chat with one of your contacts!

Okay, good. He's gonna release the computers for you and allow you to log into NSLDS.

Web Ambassador Training on the CMS

Working with the Ektron Content Management System

REDUCING YOUR MICROSOFT OUTLOOK MAILBOX SIZE

Snow Inventory. Installing and Evaluating

Forms Printer User Guide

Module 2 Cloud Computing

mylittleadmin for MS SQL Server 2005 from a Webhosting Perspective Anthony Wilko President, Infuseweb LLC

Lab 5 Managing Access to Shared Folders

OneDrive for Business FAQ s Updated 6/19/14

Introduction to Microsoft Outlook Web Access Faculty/Staff Tutorial

How To Restore Your Data On A Backup By Mozy (Windows) On A Pc Or Macbook Or Macintosh (Windows 2) On Your Computer Or Mac) On An Pc Or Ipad (Windows 3) On Pc Or Pc Or Micro

Word 2010: Mail Merge to with Attachments

CRM CUSTOMER RELATIONSHIP MANAGEMENT

Chapter 14: Links. Types of Links. 1 Chapter 14: Links

How To Sync Between Quickbooks And Act

Document Management User Guide

Access Control and Audit Trail Software

Create a New Database in Access 2010

From Data Modeling to Data Dictionary Written Date : January 20, 2014

Online Guide of Frequently Asked Questions about MyCardStatement.com

Over the past several years Google Adwords has become THE most effective way to guarantee a steady

ACS Backup and Restore

The Power Loader GUI

ODBC Overview and Information

Part II. Managing Issues

12Planet Chat end-user manual


PORTAL ADMINISTRATION

Using Google Docs in the classroom: Simple as ABC

ICP Data Entry Module Training document. HHC Data Entry Module Training Document

How To Build An Intranet In Sensesnet.Com

Version 4.1 USER S MANUAL Technical Support (800)

MS Access Lab 2. Topic: Tables

Timeless Time and Expense Version 3.0. Copyright MAG Softwrx, Inc.

Managing Files. On a PC, after you find your file, right click it and selet Rename from the pop-up menu.

ERserver. iseries. Work management

Example of Implementing Folder Synchronization with ProphetX

Index. Page 1. Index

Managing Your box

Magento Clang Integration Extension version 1.2.0

Start Learning Joomla!

Microsoft Word 2010 Mail Merge (Level 3)

SOS SO S O n O lin n e lin e Bac Ba kup cku ck p u USER MANUAL


Creating Database Tables in Microsoft SQL Server

1.5 MONITOR. Schools Accountancy Team INTRODUCTION

File Management Windows

How To Backup A Database In Navision

Managing documents, files and folders

You must have at least Editor access to your own mail database to run archiving.

DESIGN A WEB SITE USING PUBLISHER Before you begin, plan your Web site

Moving BidMagic to a new system (Backup / Restore Utility)

File Management Where did it go? Teachers College Summer Workshop

Migrate Joomla 1.5 to 2.5 with SP Upgrade

Expat Tracker. User Manual HR Systems Limited

Copyright Texthelp Limited All rights reserved. No part of this publication may be reproduced, transmitted, transcribed, stored in a retrieval

TAMS Analyzer 3 and Multi-User Projects. By Matthew Weinstein

Getting Started with WebSite Tonight

Publishing Geoprocessing Services Tutorial

In the same spirit, our QuickBooks 2008 Software Installation Guide has been completely revised as well.

Librarian. Integrating Secure Workflow and Revision Control into Your Production Environment WHITE PAPER

>> My name is Danielle Anguiano and I am a tutor of the Writing Center which is just outside these doors within the Student Learning Center.

(These instructions are only meant to get you started. They do not include advanced features.)

USING WORDPERFECT'S MERGE TO CREATE MAILING LABELS FROM A QUATTRO PRO SPREADSHEET FILE Click on a Step to move to the next Step

Regain Your Privacy on the Internet

Section 9. Topics Covered. Using the Out of Office Assistant Working offline Time Required: 30 Mins

Opera 3 Installation & Upgrade Guide

Core Essentials. Outlook Module 1. Diocese of St. Petersburg Office of Training

So you want to create an a Friend action

The QuickBooks Extension

Figure 1: Restore Tab

Importing TSM Data into Microsoft Excel using Microsoft Query

If the database that is required is similar to a template then whole database can be generated by using a template that already exists.

Hyper-Cluster. By John D. Lambert, Microsoft SQL Server PFE

Autodownloader Toolset User Guide

Google Apps Migration

FTP Use. Internal NPS FTP site instructions using Internet Explorer:

Flexible Virtuemart 2 Template CleanMart (for VM2.0.x only) TUTORIAL. INSTALLATION CleanMart VM 2 Template (in 3 steps):

Writer Guide. Chapter 15 Using Forms in Writer

Installation Guide - Client. Rev 1.5.0

Microsoft Outlook. KNOW HOW: Outlook. Using. Guide for using , Contacts, Personal Distribution Lists, Signatures and Archives

Transcription. Crashplan vs Backblaze. Which service should you pick the short version

Secrets From OfflineBiz.com Copyright 2010 Andrew Cavanagh all rights reserved

JMM Software Suite

Installing WordPress MU

How To Manage Your Storage In Outlook On A Pc Or Macintosh Outlook On Pc Or Pc Or Ipa On A Macintosh Or Ipad On A Computer Or Ipo On A Laptop Or Ipod On A Desktop Or Ipoo On A

1.2 Using the GPG Gen key Command

Quick Start Articles provide fast answers to frequently asked questions. Quick Start Article

Managing User Accounts and User Groups

USERS MANUAL FOR OWL A DOCUMENT REPOSITORY SYSTEM

Using Delphi Data with Excel and Access

TRANSFORM YOUR MEDE8ER TV WALL FROM THIS: TO THIS: LIBRARY VIEW SHOW VIEW SEASON VIEW FULL SYNOPSIS AND INFO

Polycom Converged Management Application (CMA ) Desktop for Mac OS X. Help Book. Version 5.1.0

List of some usual things to test in an application

Mesa DMS. Once you access the Mesa Document Management link, you will see the following Mesa DMS - Microsoft Internet Explorer" window:

Transcription:

Seite 1 von 5 Issue Date: FoxTalk November 2000 Simple Document Management Using VFP, Part 1 Russell Campbell russcampbell@interthink.com Some clients seem to be under the impression that they need to store information outside of Visual FoxPro, a trend not worth fighting if you don't want to write a word processor or spreadsheet using VFP. However, those same clients will often ask you to manage their documents using VFP. In this article, the first in a series, Russell Campbell explains one way of using VFP to help clients more easily access and manage their documents. The second article will delve deeper into this subject to show how a more extensive and fullfeatured document management system can be built with VFP. Document management via the Internet will be explored in the final article. Remember those claims from early in the computer age? One of the most common predictions referred to the "paperless office." Have you seen an office like that? I haven't. In fact, it seems that computers generate much more paper than ever. There are word processing documents, spreadsheets, presentations, newsletters, graphics, CAD drawings, and many more. My clients often find themselves awash in a sea of documents and need a sane way to organize the flood. Bonfires come to mind, but that never goes over well, so I created a set of classes to do some basic document management. When I first started thinking about document management using VFP, I was working with a client that had a large number of documents already in existence. They had a large client base and had done a number of projects for each client. Each project generated a fairly large number of documents, so they had more than a gigabyte worth of documents, with more being added every day. As a result, specific requirements arose from their environment, as well as from my own analysis. Requirements The first requirement was that they still be able to access these documents in the normal fashion (they'd worked out a directory structure to "organize" things) instead of via a full-fledged, "protected" document management system (DMS). The reasoning behind this was as follows: They couldn't put the existing documents in a protected DMS because it would be very difficult to associate them with at least one record in one table in the system (see requirement two in the next paragraph). Trying to put only the new documents in a protected system would have resulted in documents being stored in two locations, with old documents only accessible via the usual methods and new documents only accessible via the DMS. Due to these constraints, we decided to continue storing the documents on the server within the directory structure they'd created. The second requirement was that the new and existing documents should be able to be associated with certain aspects of a project, such as a bill of materials, a sales order, a purchase order, and so on. By doing this, we'd be able to display a list of documents associated with any record in any table in the system when that record was displayed on a form. Before I detail the third requirement, which came from my perspective, let me explain the design idea I tossed out. As I mentioned, the second requirement was that I be able to associate any record in any table with one or more documents. When a particular record was displayed on a form, I wanted the user to be able to easily see all of the documents associated with that record (the record might be an invoice, bill of materials, sales order, purchase order, and so forth). I toyed with the idea of a separate form that would display the documents associated with the current record on the active form, but I abandoned that idea as overly complex and problematic. (How would it stay in synch with open forms? How would it display documents when the same form was opened twice, but each instance was displaying a different record? As the active form was changed, the document management form would need to update itself. Would this result in too much network traffic? Would spreading data over two forms confuse the user?) So I decided that my third goal would be to design a container class that would add document management capabilities to a form when the class was dropped onto the form (thereby allowing the user to see all of the documents associated with the currently displayed record). On top of that, I didn't want to have to make any significant changes to my form class in order to support the document management class, if it was present on a form. Execution Taking the first requirement under consideration, I knew that the system would have to store a link to the document. By using a link, I could let the users choose where to save a new document on disk, and therefore allow them to access it from

Seite 2 von 5 Windows Explorer or elsewhere. This immediately raised an issue about drive mappings. Although this client had some standard mappings that were set up in the login scripts, the drive that pointed to the documents directory wasn't consistent. One user was testing the system, and on his computer the E: drive mapped to the documents directory, but on other computers I couldn't count on the same drive letter being mapped to the same place. Enter the Uniform Naming Convention (UNC). I knew that I could point to files using UNC, but I wasn't really sure how to convert a standard drive/path/filename to a UNC name. There had to be a Windows API call for that, I thought, and there was, but finding it took a little while. My first problem was that I blanked out on the exact name of UNC. I found the name referenced in MSDN, but I had some trouble finding anything that told me how to get a UNC name from a standard drive/path/filename. But before too long I found the WNetGetConnection function. This function retrieves the name of the network resource associated with a local device, so you can pass it a drive letter and it returns a UNC name for that drive. Then it's just a matter of sticking the path and filename onto the name of the network resource returned by WNetGetConnection. Problem solved. The second requirement also presented me with a bit of a problem. The idea called for the user to be able to associate a document with any type of record in the system. For instance, the user might want to associate one document with a specific sales order (SO) and another with a specific purchase order (PO). I figured the thing to do would be to associate the documents with the primary key of the record in question (an SO or PO record, in my example), but since I was using surrogate keys, and they started at one for each table, both the SO and PO table might each have had a record that used the same number (in fact, this was quite likely). Associating a document with primary key 123, for instance, would cause the same documents to be pulled up for both the SO and PO records whose primary keys were 123. It was obvious that I'd have to combine the table name with the primary key to get a unique identifier. I did this by using two fields in the document management table (I'll explain the table structure of the DOC_MGR table later in the article). One field (MODULE) stored the table with which a document was associated, and the other (MODULE_KEY) stored the primary key of the record. Combining these two fields gave me the unique key that I needed. As I've mentioned, the third requirement was my own. I wanted to be able to easily add document management capabilities to any form by just dropping a container class on the form. This container class, which I named cntdocmgr, would handle the document management. It does all of the work of document management, and no real changes are required to the form on which it's placed. I'll go into more detail about cntdocmgr soon enough, but first I'll mention the second part of the third requirement. This second part was that I didn't want to have to make any significant changes to my base-level form class in order to support the cntdocmgr class. The change I did end up making was to add two properties (DocMgrExists and DocMgrRef) to my base form. The DocMgrExists form property is populated by the document manager class (cntdocmgr). It defaults to False, but when a document manager object exists on a form, it's set to True by cntdocmgr (actually, I could probably do without this property, but it adds readability to the code). Look at the Init method of the cntdocmgr class to see where this is done. The DocMgrRef form property is simply a reference to the document manager object, and it's also set by the document manager object when it initializes. Once these two properties are added to your base form, you're just a few steps away from adding document management to a form by using the two classes I've created. Two classes, you ask? Yes, there's one more class, and it's used by cntdocmgr. It's a form class called frmdocmgradd, and it's used to collect certain information about a document. For instance, when the user wants to add a new document, cntdocmgr instantiates frmdocmgradd to collect the name of the document where it should be stored. It's a modal form, so the user must supply the required information (or cancel) before control is returned to the form on which cntdocmgr resides. If you run the sample app, open the sales order form, and click on the Link to Existing button (which is within the cntdocmgr class), you'll see an instance of the frmdocmgradd form. Now I'll detail how to use these classes. Using the document manager class The first step is simply to drop the cntdocmgr class onto the form. I often use the interface style from the VFP Tas Traders sample app, where table maintenance is done on one (or more) page(s) of a pageframe, and the user locates records on the last page, which is the "List" page. With this in mind, I add another page to the pageframe, move the List page's controls to the last page, and use the new page for the document management page. This keeps document management separate, since the user employs this feature less often, and gives the document management control the room it needs. The next step is to set the Module property of the class. It should be populated with a three-character abbreviation for the main table of the form on which you've added document management. The Module property is used to populate the MODULE field in the DOC_MGR table (the structure of the DOC_MGR table is shown in Table 1). Each time a record is added to the DOC_MGR table, the value stored in the Module property is used to populate the MODULE field. As mentioned previously, combining the table name (or, in this case, a three-character code to indicate the table name) with the primary key from a record in one of your program's tables allows the system to link documents with specific records in specific tables. Table 1. Structure of the DOC_MGR table. Field Type Len KEY_FLD INTEGER 4

Seite 3 von 5 MODULE CHARACTER 3 MODULE_KEY CHARACTER 20 NICE_NAME CHARACTER 40 DOC_NAME MEMO 4 The third step is to make a call to the RetrieveDocs method of the cntdocmgr class in the form's Refresh method. You can see an example of this in the Refresh method of the SO form included with the sample application. This involves three lines of code, so it's not difficult. That's it. It's pretty simple, but then that's the goal here simple document management. Now I'll delve into the innards of the classes. The cntdocmgr class is the only class that's dropped onto a form, but it makes use of the frmdocmgradd class. The cntdocmgr class allows the user to edit a document, delete a document link (and the document itself, if requested), create a new document and add a link to it, make a copy of an existing document and add a link to it, or link to an existing document. Additionally, you can relink to a document (in case the document has moved) and rename the link (each link has a "friendly name" separate from the document name). The cntdocmgr class is shown in Figure 1. Figure 1: The cntdocmgr class in use on a form. The cntdocmgr class is fairly straightforward. It has a list box to display the documents associated with the current record, and seven buttons to accomplish its tasks. The list box is populated from an array called DocsArray (you'll find I'm not a fan of Hungarian notation). It's a two-column array, with the first column containing the "friendly name" of the document (pulled from the NICE_NAME field) and the second column containing the primary key value for the associated record in the DOC_MGR table. As the user moves through the records in the form's main table, this list box is updated to display all of the documents associated with the main table's current record. You can see this by running the sample application, pulling up the SO form, and moving through the records in that table. The buttons allow the user to perform various tasks, such as editing a document, deleting a document, creating a new document, copying an existing document, linking to an existing document, relinking an existing entry to a document that might have moved, and renaming an existing link. The methods that these buttons execute have names such as AddDoc, EditDoc, DeleteDoc, and LinkDoc. You can look at the sample files to get the details, but basically they instantiate frmdocmgradd, retrieve the necessary information from that form, create (or not) a record in DOC_MGR, populate it appropriately, and then call RetrieveDocs to update the list box. Next, I'll give you an overview of the frmdocmgradd class. Since this class is multipurpose, it uses a three-page pageframe (sans tabs), and the appropriate page is activated depending on the operation being performed. This could be done based on a parameter, but I'm letting the calling method do that directly. The first page (shown in Figure 2) is used when the user wants to add a new document, so I'll explain it first. Figure 2: The frm DocMgrAdd class displaying page 1 of the pageframe in order to add a new document. When the user clicks Add New from the cntdocmgr control, frmdocmgradd is instantiated and page 1 is activated. From here, the user may select the type of document to create, assign its name and where to store it, and give the document a friendly name. Clicking the Add button creates the document and opens it for editing. The Document Type list box displays the types of documents that can be created. Windows knows what documents you can create, and it will display a list of them if you select File New in the Windows Explorer. There might be an API call to retrieve that list, and, if so, that API call and the resulting list could be employed by these classes. Unfortunately, that list contains a number of items you might not want to appear in your Document Type list. It's also possible to maintain a table of the document types, but I decided to handle this in a different fashion. Underneath the sample program's main folder is a folder called Templates. The Templates folder, in turn, contains folders representing the document types. If you look at the directory structure for the sample app, you'll see that the Templates folder contains three folders called Excel, Power Point, and Word. These folder names are displayed in the Document Types list box. The contents of the document type folders are displayed in the Document Template list box. Look again at the directory structure for the sample app and you'll see that the Templates\Word folder contains two documents called "Thank you letter" and "Word document." When a document is created, the system simply copies these document types to the folder the user has selected and renames the document to the name that the user has chosen. To create new document types, the user just adds a new folder under the Templates folder and places one or more template files within it (please note that these aren't true templates such

Seite 4 von 5 as you're used to in Word; they're just regular documents that are used to create a new document via a copy process). After selecting the type of document and the template to use, the user must indicate where to create the new document and what to call it. This is done by clicking the Document Name button. A standard Save As dialog box appears to collect the required information. After this information is collected, the Friendly Name is populated using the document name minus the extension. This, of course, can be changed to anything the user desires. When the user clicks the Add button, the frmdocmgradd form is closed and control is returned to the cntdocmgr class (on your form). Then the Document List list box on the cntdocmgr control is updated with the friendly name of the new document, and the document is opened for editing. The next type of operation a user can perform is to copy an existing document. This allows the user to make a copy of an existing document, create a link to the copy, and make the necessary changes. When the user clicks Copy Existing from the cntdocmgr control, frmdocmgradd is instantiated and page 2 of the pageframe, shown in Figure 3, is activated. Figure 3: The frm DocMgrAdd class displaying page 2 of the pageframe in order to copy an existing document. Whenever a copy is made of a document, there are two ways to select the original document. One way is to select it from the list of documents associated with another record, and the other is to select it directly from where it resides. These two methods of selecting the original document make this operation a bit more complex than the others. If the user wants to select the original document by viewing a list of the documents associated with a certain record in the system, then the user will employ the "Select from existing record" option (the default method of selecting the original document). This allows him or her to select a particular record in the system and see the documents associated with that record. The document that the user wishes to copy is then selected. This is done by clicking Select Original Record, viewing a pick list of records such as sales orders, and selecting the desired record, at which time the documents associated with that record are displayed in the list box. The user then selects the original document from the list box and clicks the New Doc button to indicate its new name and where it should be stored. Sounds easy enough, but this method of selecting the original document adds some complexity to the system and requires a bit of work on the part of the developer to make it function properly. The problem is that the controls have no idea how to display records from your tables, so you have to tell them how to do this. When I was first developing these controls, I thought that maybe the developer would always have to subclass them and add the necessary code to tell them how to display records from the underlying system's tables. But I didn't like that, because it required a subclass for each form on which the controls were used. This clutters the project and adds to the size of the executable file. Using my method, you never have to subclass the controls. What you do is drop the cntdocmgr control on a form and then, in the SetupCopyOptions method of cntdocmgr, add the code to tell frmdocmgradd how to display the records in your tables. You might use a BROWSE window, or you might use a form-based pick list that you've developed, but the point is that you tell it how to display the records. This also leads to some interesting references, as you can see in the sample app. The cntdocmgr control has an object reference to frmdocmgradd, which in turn has a reference back to cntdocmgr. When the user wants to select a document associated with another record in the system, frmdocmgradd executes the SetupCopyOptions method on cntdocmgr (the object that called frmdocmgradd). It's not as convoluted as it might sound, and it works quite nicely while making subclassing unnecessary and keeping EXE size at a minimum. The second method of selecting the document that's to be copied is simply to select it from where it resides on disk. Needless to say, this is the easiest method, since it just involves a call to the VFP GetFile() function. The user clicks the Original Doc button, selects the file to be copied, clicks the New Doc button to indicate where to put it and what to call it, and then clicks the Copy button to perform the action and open the document for editing. The last type of operation is simply to create a link to an existing document. Nothing new is created or copied; the user is simply saying, "Here's an existing document, please create a link to it and associate it with this record." To do this, the user clicks the Link to Existing button on the cntdocmgr control. This instantiates frmdocmgradd and displays page three of the pageframe, which is shown in Figure 4. Figure 4: The frm DocMgrAdd class displaying page 3 of the pageframe in order to link to an existing document. Linking to an existing file is the simplest of the three main types of operations that can be performed. The user merely has to select the original document and click the Link button. The other two operations allowed by the system are Relink, where the user selects an existing link and tells the system where the document is (if, for instance, the document has been moved), and Rename Link, where the user simply changes the friendly name of an existing link. The sample application The sample application, included in the accompanying Download file, should be a big help in understanding the workings of these two classes. The commenting is pretty extensive, so it should provide answers to questions that I might not have addressed or fully answered in the article. I've designed the classes and the library in which they are stored so that it's a

Seite 5 von 5 standalone library. This should allow you to immediately put the classes to use on your forms with minimal modifications. When you start the sample app, you should look at the Sales Orders form off the Edit menu. Move around to various records and watch how the list of linked documents changes. Try to add a new document or link to an existing one. Look at the underlying source code. The Purchase Orders form is provided just as a quick way to toy with the classes. The form is empty, but you can make your own additions to it and add the cntdocmgr control to see how to use it in the development environment. Final thoughts The controls I've presented in this article aren't for everyone. They work best when you find yourself in a situation similar to mine: lots of existing documents, no great need for high security, a desire to access documents in the usual fashion as well as through your VFP application, and a client for whom change comes at an evolutionary (vs. revolutionary) pace. In the next installment of this series, I'll present a more extensive set of classes that allow for a much more feature-filled DMS, including logging, security, and the ability to handle version control. As I mentioned at the outset, the final article in the series will explore ways to handle document management over the Internet.