Document Manager Documentation¶
File: visiowings/document_manager.py
Overview¶
The Document Manager is responsible for discovering and managing multiple Visio documents (drawings, stencils, templates) within a single editing session. It provides a unified interface for accessing VBA projects across all open documents.
Core Classes¶
VisioDocumentInfo¶
Data class representing a single Visio document.
Attributes:
class VisioDocumentInfo:
doc: COM Object # win32com.client Visio.Document
name: str # Display name (e.g., "MyDrawing")
doc_type: str # "Drawing" | "Stencil" | "Template"
folder_name: str # Folder name for exports (e.g., "mydrawing")
full_name: str # Full file path
has_vba: bool # True if document has VBA project
Example:
VisioDocumentInfo(
doc=<COM Object>,
name="MyDrawing.vsdm",
doc_type="Drawing",
folder_name="mydrawing",
full_name="C:\\Projects\\MyDrawing.vsdm",
has_vba=True
)
VisioDocumentManager¶
Manages discovery and access to all relevant Visio documents.
Constructor:
Key Methods:
- connect_to_visio() - Establish COM connection
- get_all_documents_with_vba() - List all documents with VBA
- get_main_document() - Get primary document
- print_summary() - Display discovered documents
Document Discovery¶
Algorithm¶
-
Connect to Visio Application
-
Find Main Document
- Iterate through
visio_app.Documents -
Match by
FullNameorNameagainstvisio_file_path -
Discover Referenced Documents
- Check main document's stencils
- Check templates
-
Identify related drawings
-
Filter VBA Projects
- Test each document:
doc.HasVBProject - Skip documents without VBA
Document Type Detection¶
def _get_document_type(doc) -> str:
try:
if doc.Type == 1: # visDrawing
return "Drawing"
elif doc.Type == 2: # visStencil
return "Stencil"
elif doc.Type == 3: # visTemplate
return "Template"
except:
pass
return "Unknown"
Folder Name Generation¶
def _generate_folder_name(doc_name: str) -> str:
# Remove extension
base_name = Path(doc_name).stem
# Sanitize for file system
folder_name = base_name.lower()
folder_name = folder_name.replace(' ', '_')
folder_name = ''.join(c for c in folder_name if c.isalnum() or c == '_')
return folder_name
Examples:
- "My Drawing.vsdm" → "my_drawing"
- "Company-Stencil.vssx" → "companystencil"
- "Template 2.0.vstx" → "template_20"
Multi-Document Scenarios¶
Scenario 1: Drawing with Custom Stencil¶
Open Documents:
- Project.vsdm (main drawing)
- CustomShapes.vssm (stencil with VBA)
Export Structure:
vba_modules/
├── project/
│ ├── Module1.bas
│ └── ThisDocument.cls
└── customshapes/
├── ShapeHelper.bas
└── ThisDocument.cls
Scenario 2: Template Development¶
Open Documents:
- MyTemplate.vstx (template)
- TemplateStencil.vssx (stencil)
Export Structure:
VBA Project Access¶
Checking VBA Presence¶
def has_vba_project(doc) -> bool:
try:
vb_project = doc.VBProject
if vb_project.VBComponents.Count > 0:
return True
except:
pass
return False
Accessing Components¶
for doc_info in manager.get_all_documents_with_vba():
vb_project = doc_info.doc.VBProject
for component in vb_project.VBComponents:
print(f"{doc_info.name}: {component.Name}")
Summary Output¶
Single Document¶
Multiple Documents¶
📝 Main Document: MyDrawing.vsdm
Type: Drawing
VBA: Yes
📄 Additional Documents:
• CustomStencil.vssm (Stencil, VBA: Yes)
• SharedTemplate.vstx (Template, VBA: No - skipped)
ℹ️ Total documents with VBA: 2
Error Handling¶
Connection Failures¶
def connect_to_visio(self) -> bool:
try:
self.visio_app = win32com.client.GetActiveObject("Visio.Application")
# Find main document...
return True
except:
print("❌ Visio not running or document not open")
return False
Document Access Errors¶
try:
vb_project = doc.VBProject
except:
# Missing VBA access permission
print("⚠️ Enable 'Trust access to VBA project object model'")
Performance Considerations¶
Lazy Discovery¶
Documents are discovered once during initialization:
def __init__(self, visio_file_path, debug=False):
self._documents_cache = None # Populated on first access
COM Object Reuse¶
Document COM objects are reused throughout the session:
Thread Safety¶
Document Manager is not thread-safe. Create separate instances for different threads:
# Main thread
exporter_manager = VisioDocumentManager(file_path)
# Watcher thread
importer_manager = VisioDocumentManager(file_path)
Debugging¶
With debug=True:
[DEBUG] Connecting to Visio...
[DEBUG] Found main document: MyDrawing.vsdm
[DEBUG] Scanning for additional documents...
[DEBUG] Found stencil: CustomStencil.vssm
[DEBUG] Document map created: ['mydrawing', 'customstencil']
Best Practices¶
Always Check Connection¶
Cache Document List¶
# Good - cache results
docs_with_vba = manager.get_all_documents_with_vba()
for doc_info in docs_with_vba:
# process...
# Avoid - repeated discovery
for doc_info in manager.get_all_documents_with_vba(): # Repeated calls
# ...