|
|
Line 9: |
Line 9: |
| Items deleted from the saver-list may still be saved; something inside the XML objects is remembering them. You have to destroy the main Setting object and rebuild it at save-time in order to prevent this from happening. Fortunately, this doesn't seem to slow anything down noticeably. | | Items deleted from the saver-list may still be saved; something inside the XML objects is remembering them. You have to destroy the main Setting object and rebuild it at save-time in order to prevent this from happening. Fortunately, this doesn't seem to slow anything down noticeably. |
| ==Code== | | ==Code== |
− | ===clsSettingAPI===
| + | * [[User:Woozle/VB/Settings manager/sample code|sample code]]: how to use the class collection |
− | This is an abstract class for translating between internal data and the string to actually save. It is implemented by [[#clsSettingText]] and [[#xtForm]].
| + | * [[User:Woozle/VB/Settings manager/source code|source code]]: the classes themselves |
− | <pre>
| |
− | Option Explicit
| |
− | | |
− | ' CLASS: clsSettingAPI
| |
− | ' PURPOSE: abstract class for saving a single item's settings
| |
− | Public Name As String
| |
− | Public Value As String
| |
− | Public Sub Save(iNode As clsSettingsNodeAPI)
| |
− | ' abstract
| |
− | End Sub
| |
− | Public Sub Load(iNode As clsSettingsNodeAPI)
| |
− | ' abstract
| |
− | End Sub
| |
− | </pre>
| |
− | ===clsSettingsAPI===
| |
− | <pre>
| |
− | Option Explicit
| |
− | | |
− | ' CLASS: clsSettingsAPI
| |
− | ' PURPOSE: abstract settings-saving class
| |
− | | |
− | Public Function Root() As clsSettingsNodeAPI
| |
− | ' ACTION: Return the root node
| |
− | ' USAGE: abstract; this is model code:
| |
− | Dim objRoot As clsSettingsNodeAPI
| |
− |
| |
− | Set objRoot = New clsSettingsNodeAPI
| |
− | objRoot.Init Me, Nothing
| |
− | Set Root = objRoot
| |
− | End Function
| |
− | Public Sub Load(iForce As Boolean)
| |
− | ' abstract
| |
− | End Sub
| |
− | Public Sub Save()
| |
− | ' abstract
| |
− | End Sub
| |
− | Private Sub Class_Initialize()
| |
− | ' abstract; sample code
| |
− | Me.Load False
| |
− | End Sub
| |
− | Private Sub Class_Terminate()
| |
− | ' abstract; sample code
| |
− | Me.Save
| |
− | End Sub
| |
− | </pre>
| |
− | ===clsSettingsNodeAPI===
| |
− | <pre>
| |
− | ' CLASS: clsSettingsNodeAPI
| |
− | ' PURPOSE: set of values for clsSettingsAPI
| |
− | ' USAGE: Abstract
| |
− | | |
− | Option Explicit
| |
− | Private objMain As clsSettingsAPI
| |
− | Private objParent As clsSettingsNodeAPI
| |
− | Friend Sub Init(iSettings As clsSettingsAPI, iParent As clsSettingsNodeAPI)
| |
− | Set objMain = iSettings
| |
− | Set objParent = iParent
| |
− | End Sub
| |
− | Public Property Get Name() As String
| |
− | ' abstract
| |
− | End Property
| |
− | Public Function Node(iName As String, iCreate As Boolean) As clsSettingsNodeAPI
| |
− | ' ACTION: Return the root node
| |
− | ' USAGE: abstract; this is model code:
| |
− | Dim objNode As clsSettingsNodeAPI
| |
− |
| |
− | Set objNode = New clsSettingsNodeAPI
| |
− | ' find subnode with name iName; initialize objNode with it (not Nothing)
| |
− | objNode.Init Me, Nothing
| |
− | Set Node = objNode
| |
− | End Function
| |
− | Public Function AddItem(iItem As clsSettingAPI) As clsSettingsNodeAPI
| |
− | ' ACTION: Add an item to the tree; return the item's node object
| |
− | ' abstract
| |
− | End Function
| |
− | Public Property Get ValueStored() As String
| |
− | ' ACTION: Returns the *stored* value (not the active value)
| |
− | ' abstract
| |
− | End Property
| |
− | Public Property Let ValueStored(iValue As String)
| |
− | ' ACTION: Sets the *stored* value (not the active value)
| |
− | ' abstract
| |
− | End Property
| |
− | Public Sub Load()
| |
− | ' abstract
| |
− | End Sub
| |
− | Public Sub Save()
| |
− | ' abstract
| |
− | End Sub
| |
− | Public Property Get ListNodes() As Scripting.Dictionary
| |
− | ' abstract
| |
− | End Property
| |
− | </pre>
| |
− | ===clsSettingsXML===
| |
− | <pre>
| |
− | Private strSection As String
| |
− | Private strAppName As String
| |
− | Private strFileSpec As String
| |
− | Private xmlDoc As MSXML2.DOMDocument
| |
− | Private objRoot As clsSettingsNodeXML
| |
− | Private isLoaded As Boolean
| |
− | Public Sub Init(Optional iSection As String = "", Optional iAppName As String = "")
| |
− | If iSection <> "" Then
| |
− | strSection = iSection
| |
− | End If
| |
− | If iAppName <> "" Then
| |
− | strAppName = iAppName
| |
− | End If
| |
− |
| |
− | strFileSpec = App.Path & "\" & App.Title & ".prefs.xml"
| |
− | isLoaded = False
| |
− | End Sub
| |
− | Public Function Root() As clsSettingsNodeAPI
| |
− | ' ACTION: Return the root node
| |
− | ' Dim objRootSet As clsSettingText
| |
− | Dim xmlRoot As MSXML2.IXMLDOMNode
| |
− |
| |
− | If objRoot Is Nothing Then
| |
− | ' Set objRootSet = New clsSettingText
| |
− | ' objRootSet.Init strSection, ""
| |
− | Set objRoot = New clsSettingsNodeXML
| |
− | With Me.GetXMLDoc
| |
− | If .childNodes.Length = 0 Then
| |
− | Stop ' this should never happen - GetXMLDoc is supposed to create the root node
| |
− | Else
| |
− | Set xmlRoot = .firstChild
| |
− | End If
| |
− | End With
| |
− | objRoot.InitRoot strSection, xmlRoot, Me
| |
− | End If
| |
− | Set Root = objRoot
| |
− | End Function
| |
− | Public Property Get FileSpec() As String
| |
− | FileSpec = strFileSpec
| |
− | End Property
| |
− | Public Property Let FileSpec(iSpec As String)
| |
− | strFileSpec = iSpec
| |
− | End Property
| |
− | Public Sub Load(iForce As Boolean)
| |
− | ' ACTION: Read settings data from file
| |
− | If iForce Or (Not Me.Loaded) Then
| |
− | Me.GetXMLDoc.Load Me.FileSpec
| |
− | ' Set xmlDoc = Nothing ' loading the document clears all nodes
| |
− | isLoaded = True
| |
− | End If
| |
− | End Sub
| |
− | Public Sub Save()
| |
− | ' Dim objNode As clsSettingsNodeXML
| |
− |
| |
− | ' Set objNode = Me.Root
| |
− | ' objNode.Save
| |
− | Me.GetXMLDoc.Save Me.FileSpec
| |
− | isLoaded = True
| |
− | End Sub
| |
− | Public Function Loaded() As Boolean
| |
− | Loaded = isLoaded
| |
− | End Function
| |
− | Friend Function GetXMLDoc() As MSXML2.DOMDocument
| |
− | Dim xmlRoot As MSXML2.IXMLDOMNode
| |
− |
| |
− | ' create document if needed
| |
− | If xmlDoc Is Nothing Then
| |
− | Set xmlDoc = New MSXML2.DOMDocument
| |
− | End If
| |
− |
| |
− | ' create root node if needed
| |
− | If xmlDoc.childNodes.Length = 0 Then
| |
− | With xmlDoc
| |
− | ' create the root node
| |
− | Set xmlRoot = .createNode(NODE_ELEMENT, strSection, "")
| |
− | .appendChild xmlRoot
| |
− | End With
| |
− | End If
| |
− | Set GetXMLDoc = xmlDoc
| |
− | End Function
| |
− | Private Sub Class_Initialize()
| |
− | strSection = "settings" ' default
| |
− | strAppName = App.EXEName
| |
− | End Sub
| |
− | Private Sub clsSettingsAPI_Load(iForce As Boolean)
| |
− | Me.Load iForce
| |
− | End Sub
| |
− | Private Function clsSettingsAPI_Root() As clsSettingsNodeAPI
| |
− | clsSettingsAPI_Root = Me.Root
| |
− | End Function
| |
− | Private Sub clsSettingsAPI_Save()
| |
− | Me.Save
| |
− | End Sub
| |
− | ===clsSettingsNodeXML===
| |
− | <pre>
| |
− | Option Explicit
| |
− | | |
− | Implements clsSettingsNodeAPI
| |
− | | |
− | Private strName As String
| |
− | Private objMain As clsSettingsXML
| |
− | Private objParent As clsSettingsNodeXML
| |
− | Public XMLNode As MSXML2.IXMLDOMNode
| |
− | Private objItem As clsSettingAPI
| |
− | Private lstNodes As Scripting.Dictionary ' list of sub-nodes
| |
− | Private lstXMLs As Scripting.Dictionary ' list of XML sub-nodes (refresh before using)
| |
− | Friend Sub Init(iItem As clsSettingAPI, iXML As MSXML2.IXMLDOMNode, iParent As clsSettingsNodeAPI)
| |
− | Set objItem = iItem
| |
− | Set objParent = iParent
| |
− | Me.InitRoot iItem.Name, iXML, objParent.Main
| |
− | End Sub
| |
− | Friend Sub InitRoot(iName As String, iXML As MSXML2.IXMLDOMNode, iMain As clsSettingsXML)
| |
− | ' USAGES: (1) Internally, and (2) for clsSettingsXML to initialize root node only
| |
− | strName = iName
| |
− | Set XMLNode = iXML
| |
− | Set objMain = iMain
| |
− | End Sub
| |
− | Friend Sub InitHolder(iName As String, iXML As MSXML2.IXMLDOMNode, iParent As clsSettingsNodeXML)
| |
− | ' USAGE: For initializing a node when we don't yet know what Item it will have
| |
− | Me.InitRoot iName, iXML, iParent.Main
| |
− | Set objParent = iParent
| |
− | Set objItem = Nothing ' this will be set later
| |
− | End Sub
| |
− | Friend Property Set Item(iItem As clsSettingAPI)
| |
− | Set objItem = iItem
| |
− | End Property
| |
− | Friend Property Get Item() As clsSettingAPI
| |
− | Set Item = objItem
| |
− | End Property
| |
− | Friend Property Get Main() As clsSettingsXML
| |
− | Set Main = objMain
| |
− | End Property
| |
− | Friend Property Set Main(iDoc As clsSettingsXML)
| |
− | Set objMain = iDoc
| |
− | End Property
| |
− | Public Function Node(iName As String, iCreate As Boolean) As clsSettingsNodeXML
| |
− | ' ACTION: Return the node with the given name
| |
− | Dim objNode As clsSettingsNodeXML
| |
− |
| |
− | ' Set objNode = New clsSettingsNodeXML
| |
− | ' find subnode with name iName; initialize objNode with it (not Nothing)
| |
− | With Me.ListNodes
| |
− | If .Exists(iName) Then
| |
− | Set objNode = .Item(iName)
| |
− | Else
| |
− | If iCreate Then
| |
− | Set objNode = New clsSettingsNodeXML
| |
− | objNode.InitHolder iName, MakeXML(iName), Me
| |
− | Else
| |
− | Set objNode = Nothing
| |
− | End If
| |
− | End If
| |
− | End With
| |
− | Set Node = objNode
| |
− | End Function
| |
− | Public Property Get Name() As String
| |
− | Name = strName
| |
− | End Property
| |
− | Public Property Get ValueStored() As String
| |
− | ' ACTION: Returns the *stored* value (not the active value)
| |
− | If Not (XMLNode Is Nothing) Then
| |
− | ValueStored = XMLNode.Text
| |
− | End If
| |
− | End Property
| |
− | Public Property Let ValueStored(iValue As String)
| |
− | ' ACTION: Sets the *stored* value (not the active value)
| |
− | If XMLNode Is Nothing Then
| |
− | Stop ' does this ever happen?
| |
− | End If
| |
− | XMLNode.Text = iValue
| |
− | End Property
| |
− | Public Property Get ValueActive() As String
| |
− | If Not (objItem Is Nothing) Then
| |
− | ValueActive = objItem.Value
| |
− | End If
| |
− | End Property
| |
− | Public Property Let ValueActive(iValue As String)
| |
− | ' ACTION: Sets the *stored* value (not the active value)
| |
− | If Not (objItem Is Nothing) Then
| |
− | objItem.Value = iValue
| |
− | End If
| |
− | End Property
| |
− | Public Sub Load()
| |
− | ' ACTION: Read values from the XML DOM tree and stash them in clsSettingAPI objects
| |
− | Dim xmlThis As MSXML2.IXMLDOMNode
| |
− | Dim objSub As clsSettingsNodeXML
| |
− |
| |
− | ' 1. Look through the document and pull out values into the value list; save pointer to each node found
| |
− | Set xmlThis = XMLNode.firstChild
| |
− | Do While Not (xmlThis Is Nothing)
| |
− | With xmlThis
| |
− | If Not Me.ListNodes.Exists(.nodeName) Then
| |
− | ' ' this block duplicates code in me.List; should probably put it in a subroutine
| |
− | ' Set objSub = New clsSettingsNodeXML
| |
− | ' objSub.InitHolder .baseName, xmlThis, Me
| |
− | ' lstNodes.Add .baseName, Nothing
| |
− | AddHolder xmlThis
| |
− | End If
| |
− | Set objSub = Me.Node(.nodeName, False)
| |
− | objSub.ValueActive = .Text
| |
− | End With
| |
− | Set xmlThis = xmlThis.nextSibling
| |
− | Loop
| |
− | ' 2. Go through the list and call Load() recursively
| |
− | LoadSub
| |
− | End Sub
| |
− | Private Sub AddHolder(iXML As MSXML2.IXMLDOMNode)
| |
− | Dim objSub As clsSettingsNodeXML
| |
− | Dim strName As String
| |
− |
| |
− | strName = iXML.nodeName
| |
− | Set objSub = New clsSettingsNodeXML
| |
− | objSub.InitHolder strName, iXML, Me
| |
− | lstNodes.Add strName, objSub
| |
− | End Sub
| |
− | Private Sub LoadSub()
| |
− | Dim idxSub As Long
| |
− | Dim objNode As clsSettingsNodeXML
| |
− |
| |
− | For idxSub = 0 To Me.ListNodes.Count - 1
| |
− | Set objNode = Me.ListNodes.Items(idxSub)
| |
− | objNode.Load
| |
− | Next
| |
− | End Sub
| |
− | Public Sub Save()
| |
− | ' ACTION:
| |
− | Dim xmlDoc As MSXML2.DOMDocument
| |
− | Dim xmlParent As MSXML2.IXMLDOMNode
| |
− | Dim xmlThis As MSXML2.IXMLDOMNode
| |
− | Dim strName As String
| |
− |
| |
− | Set xmlDoc = objMain.GetXMLDoc
| |
− | ' ' there doesn't seem to be any way to find out if a child node already exists,
| |
− | ' ' so for now we just kill them all.
| |
− | ' Set xmlThis = xmlNode.firstChild
| |
− | ' Do While Not (xmlThis Is Nothing)
| |
− | ' Set xmlNext = xmlThis.nextSibling
| |
− | ' xmlNode.removeChild xmlThis
| |
− | ' Set xmlThis = xmlNext
| |
− | ' Loop
| |
− | ' If xmlSelf.childNodes.Length <> 0 Then Stop
| |
− | | |
− | If Not (objItem Is Nothing) Then
| |
− | objItem.Save Me ' tell the object to save itself, in case it has any sub-items
| |
− | ' Me.XMLNode.Text = objItem.Value
| |
− | End If
| |
− | ' recursively repeat for all sub-nodes:
| |
− | SaveSub
| |
− | End Sub
| |
− | Private Sub SaveSub()
| |
− | Dim idxSub As Long
| |
− | ' Dim objNode As clsSettingAPI
| |
− | ' Dim objNode As Object
| |
− | Dim objNode As clsSettingsNodeXML
| |
− | Dim strKey As String
| |
− | Dim xmlThis As MSXML2.IXMLDOMNode
| |
− |
| |
− | Set lstXMLs = ListXMLs
| |
− | With Me.ListNodes
| |
− | For idxSub = 0 To .Count - 1
| |
− | Set objNode = .Items(idxSub)
| |
− | strKey = objNode.Name
| |
− | If Not lstXMLs.Exists(strKey) Then
| |
− | ' if an XML node does not already exist, create it and add it to the parent node (i.e. Me)
| |
− | Set xmlThis = objMain.GetXMLDoc.createNode(NODE_ELEMENT, strKey, "")
| |
− | ' Don't save the data here; that's done in objNode.Save()
| |
− | ' xmlThis.Text = objNode.ValueActive
| |
− | Me.XMLNode.appendChild xmlThis
| |
− | Debug.Assert Not (xmlThis.parentNode Is Nothing)
| |
− | End If
| |
− | objNode.Save
| |
− |
| |
− | ' Debug.Print "NAME=" & strName
| |
− | ' Set xmlText = xmlDoc.createTextNode(.Items(intItem))
| |
− | ' xmlThis.appendChild xmlText
| |
− | Next
| |
− | End With
| |
− | End Sub
| |
− | Friend Property Get ListXMLs() As Scripting.Dictionary
| |
− | ' ACTION: get a list of XML subnodes
| |
− | ' maybe this is doing more processing than needed...
| |
− | Dim xmlKid As MSXML2.IXMLDOMNode
| |
− |
| |
− | Set lstXMLs = New Scripting.Dictionary
| |
− | Set xmlKid = Me.XMLNode.firstChild
| |
− | Do Until xmlKid Is Nothing
| |
− | lstXMLs.Add xmlKid.nodeName, xmlKid
| |
− | Set xmlKid = xmlKid.nextSibling
| |
− | Loop
| |
− | Set ListXMLs = lstXMLs
| |
− | End Property
| |
− | 'Friend Function GetXMLNode() As MSXML2.IXMLDOMNode
| |
− | ' Dim xmlDoc As MSXML2.DOMDocument
| |
− | ' Dim xmlRoot As MSXML2.IXMLDOMNode
| |
− | ' Dim xmlNode As MSXML2.IXMLDOMNode
| |
− | '
| |
− | ' Set xmlDoc = objMain.GetXMLDoc
| |
− | '
| |
− | ' If objParent Is Nothing Then
| |
− | ' ' need root node
| |
− | ' If xmlDoc.childNodes.Length = 0 Then
| |
− | ' ' none exists yet; create it:
| |
− | ' Set xmlNode = xmlDoc.createNode(NODE_ELEMENT, Me.Name, "")
| |
− | ' xmlDoc.appendChild xmlNode
| |
− | ' Else
| |
− | ' Set xmlNode = xmlDoc.firstChild
| |
− | ' End If
| |
− | ' Else
| |
− | ' ' create non-root node
| |
− | ' Set xmlNode = xmlDoc.createNode(NODE_ELEMENT, Me.Name, "")
| |
− | ' Set xmlRoot = objParent.GetXMLNode
| |
− | ' xmlRoot.appendChild xmlNode
| |
− | ' End If
| |
− | '
| |
− | ' Set GetXMLNode = xmlNode
| |
− | 'End Function
| |
− | Public Property Get ListNodes() As Scripting.Dictionary
| |
− | Dim xmlDoc As MSXML2.DOMDocument
| |
− | Dim xmlRoot As MSXML2.IXMLDOMElement
| |
− | Dim xmlThis As MSXML2.IXMLDOMNode
| |
− | ' Dim objNew As clsSettingsNodeXML
| |
− | | |
− | If lstNodes Is Nothing Then
| |
− | ' What is often happening at this point is that the XML document has been loaded, but items have not been assigned.
| |
− | ' So we have to set up item-nodes without knowing what objects to assign to them.
| |
− | | |
− | ' 2006-02-12 actually, this list should never be rebuilt from the XML tree. For one thing, that tree has stuff we don't want
| |
− | ' to put in the nodes list. For another, this list is maintained explicitly.
| |
− | ' Correction: unfortunately, we need to be able to list items not explicitly added, for things like dynamic lists
| |
− | Set lstNodes = New Scripting.Dictionary ' create the list object
| |
− | If Not (Me.XMLNode Is Nothing) Then
| |
− | If Me.XMLNode.nodeType <> NODE_TEXT Then
| |
− | ' text nodes get saved along with their parent
| |
− | For Each xmlThis In Me.XMLNode.childNodes
| |
− | With xmlThis
| |
− | ' Set objNew = New clsSettingsNodeXML
| |
− | ' objNew.InitHolder .baseName, xmlThis, Me
| |
− | ' lstNodes.Add .nodeName, .Text
| |
− | AddHolder xmlThis
| |
− | End With
| |
− | Next
| |
− | End If
| |
− | End If
| |
− | End If
| |
− | Set ListNodes = lstNodes
| |
− | End Property
| |
− | 'Public Property Get Exists(iName As String)
| |
− | ' Exists = Me.ListItems.Exists(iName)
| |
− | 'End Property
| |
− | Public Sub LoadTextBox(iCtrl As TextBox, Optional iName As String = "")
| |
− | Dim strName As String
| |
− |
| |
− | If iName = "" Then
| |
− | strName = iCtrl.Name
| |
− | Else
| |
− | strName = iName
| |
− | End If
| |
− | If Me.ListNodes.Exists(strName) Then
| |
− | iCtrl.Text = Me.Node(strName, False).ValueStored
| |
− | End If
| |
− | End Sub
| |
− | Public Sub SaveTextBox(iCtrl As TextBox, Optional iName As String = "")
| |
− | Dim strName As String
| |
− | Dim strValue As String
| |
− |
| |
− | If iName = "" Then
| |
− | strName = iCtrl.Name
| |
− | Else
| |
− | strName = iName
| |
− | End If
| |
− | strValue = iCtrl.Text
| |
− | Me.Node(strName, True).ValueStored = strValue
| |
− | End Sub
| |
− | Public Sub LoadChkBox(iCtrl As CheckBox, Optional iName As String = "")
| |
− | Dim strName As String
| |
− | Dim strValue As String
| |
− |
| |
− | If iName = "" Then
| |
− | strName = iCtrl.Name
| |
− | Else
| |
− | strName = iName
| |
− | End If
| |
− | strValue = Me.Node(strName, False).ValueStored
| |
− | If strValue <> "" Then
| |
− | If strValue = "0" Then
| |
− | iCtrl.Value = vbUnchecked
| |
− | Else
| |
− | iCtrl.Value = vbChecked
| |
− | End If
| |
− | End If
| |
− | End Sub
| |
− | Public Sub SaveChkBox(iCtrl As CheckBox, Optional iName As String = "")
| |
− | Dim strName As String
| |
− | Dim strValue As String
| |
− | Dim objNode As clsSettingsNodeAPI
| |
− |
| |
− | If iName = "" Then
| |
− | strName = iCtrl.Name
| |
− | Else
| |
− | strName = iName
| |
− | End If
| |
− | Set objNode = Me.Node(strName, True)
| |
− | If iCtrl.Value Then
| |
− | strValue = "1"
| |
− | Else
| |
− | strValue = "0"
| |
− | End If
| |
− | objNode.ValueStored = strValue
| |
− | End Sub
| |
− | Public Sub LoadCombo(iCombo As ComboBox, Optional iName As String = "")
| |
− | Dim strName As String
| |
− | Dim strValue As String
| |
− | Dim idxValue As Long
| |
− |
| |
− | If iName = "" Then
| |
− | strName = iCombo.Name
| |
− | Else
| |
− | strName = iName
| |
− | End If
| |
− |
| |
− | strValue = Me.Node(strName, False).ValueStored
| |
− | If IsNumeric(strValue) Then
| |
− | idxValue = CLng(strValue)
| |
− | If idxValue < iCombo.ListCount Then
| |
− | iCombo.ListIndex = CLng(strValue)
| |
− | End If
| |
− | End If
| |
− | End Sub
| |
− | Public Sub SaveCombo(iCombo As ComboBox, Optional iName As String = "")
| |
− | Dim strName As String
| |
− | Dim strValue As String
| |
− |
| |
− | If iName = "" Then
| |
− | strName = iCombo.Name
| |
− | Else
| |
− | strName = iName
| |
− | End If
| |
− |
| |
− | strValue = CStr(iCombo.ListIndex)
| |
− | Me.Node(strName, True).ValueStored = strValue
| |
− | End Sub
| |
− | Private Function MakeXML(iName As String) As MSXML2.IXMLDOMNode
| |
− | Dim objXML As MSXML2.IXMLDOMNode
| |
− |
| |
− | If Me.ListXMLs.Exists(iName) Then
| |
− | Set objXML = lstXMLs.Item(iName)
| |
− | Else
| |
− | Set objXML = objMain.GetXMLDoc.createNode(NODE_ELEMENT, iName, "")
| |
− | Me.XMLNode.appendChild objXML
| |
− | End If
| |
− | Set MakeXML = objXML
| |
− | End Function
| |
− | Private Function clsSettingsNodeAPI_AddItem(iItem As clsSettingAPI) As clsSettingsNodeAPI
| |
− | Dim objNode As clsSettingsNodeXML
| |
− | Dim objXML As MSXML2.IXMLDOMNode
| |
− | | |
− | If Me.XMLNode Is Nothing Then Stop
| |
− | | |
− | If Me.ListNodes.Exists(iItem.Name) Then
| |
− | Set objNode = lstNodes.Item(iItem.Name)
| |
− | Set objNode.Item = iItem
| |
− | Else
| |
− | Set objNode = New clsSettingsNodeXML
| |
− | Set objXML = MakeXML(iItem.Name)
| |
− | objNode.Init iItem, objXML, Me
| |
− | lstNodes.Add iItem.Name, objNode
| |
− | End If
| |
− | End Function
| |
− | Private Property Get clsSettingsNodeAPI_ListNodes() As Scripting.IDictionary
| |
− | Set clsSettingsNodeAPI_ListNodes = Me.ListNodes
| |
− | End Property
| |
− | Private Sub clsSettingsNodeAPI_Load()
| |
− | ' ACTION:
| |
− | ' - Load the current node's value
| |
− | ' - Iterate through children and call Load() for each
| |
− | Dim objNode As clsSettingsNodeXML
| |
− | Dim objKid As clsSettingAPI
| |
− | Dim idxKid As Long
| |
− | | |
− | If Not (objItem Is Nothing) Then
| |
− | objItem.Load Me
| |
− | End If
| |
− | For idxKid = 0 To Me.ListNodes.Count - 1
| |
− | Set objNode = lstNodes.Items(idxKid)
| |
− | Set objKid = objNode.Item
| |
− | objKid.Load objNode
| |
− | Next
| |
− | End Sub
| |
− | Private Property Get clsSettingsNodeAPI_Name() As String
| |
− | clsSettingsNodeAPI_Name = Me.Name
| |
− | End Property
| |
− | Private Function clsSettingsNodeAPI_Node(iName As String, iCreate As Boolean) As clsSettingsNodeAPI
| |
− | Set clsSettingsNodeAPI_Node = Me.Node(iName, iCreate)
| |
− | End Function
| |
− | Private Sub clsSettingsNodeAPI_Save()
| |
− | Me.Save
| |
− | End Sub
| |
− | Private Property Let clsSettingsNodeAPI_ValueStored(RHS As String)
| |
− | Me.ValueStored = RHS
| |
− | End Property
| |
− | Private Property Get clsSettingsNodeAPI_ValueStored() As String
| |
− | clsSettingsNodeAPI_ValueStored = Me.ValueStored
| |
− | End Property
| |
− | </pre>
| |
− | ===clsSettingText===
| |
− | An implementation of [[#clsSettingAPI]]
| |
− | <pre>
| |
− | Option Explicit
| |
− | | |
− | ' CLASS: clsSettingText
| |
− | ' PURPOSE: generic clsSettingAPI class for storing a text value
| |
− | ' without needing an associated control
| |
− | | |
− | Implements clsSettingAPI
| |
− | | |
− | Private strName As String
| |
− | Private strVal As String
| |
− | Public Sub Init(iName As String, iVal As String)
| |
− | strName = iName
| |
− | strVal = iVal
| |
− | End Sub
| |
− | Private Sub clsSettingAPI_Load(iNode As clsSettingsNodeAPI)
| |
− | strVal = iNode.ValueStored
| |
− | End Sub
| |
− | Private Property Let clsSettingAPI_Name(ByVal RHS As String)
| |
− | strName = RHS
| |
− | End Property
| |
− | Private Property Get clsSettingAPI_Name() As String
| |
− | clsSettingAPI_Name = strName
| |
− | End Property
| |
− | Private Sub clsSettingAPI_Save(iNode As clsSettingsNodeAPI)
| |
− | iNode.ValueStored = strVal
| |
− | End Sub
| |
− | Private Property Let clsSettingAPI_Value(ByVal RHS As String)
| |
− | strVal = RHS
| |
− | End Property
| |
− | Private Property Get clsSettingAPI_Value() As String
| |
− | clsSettingAPI_Value = strVal
| |
− | End Property
| |
− | </pre>
| |
− | ===xtForm===
| |
− | Implementation of [[#clsSettingAPI]]
| |
− | <pre>
| |
− | ' CLASS: xtForm
| |
− | ' PURPOSE: extended form functionality
| |
− | ' HISTORY:
| |
− | ' 1999.12.06 - NJS - adapted from Forms.bas
| |
− | ' 2001.01.03 - NJS - modified to use clsConfigReg for storing position
| |
− | ' 2006-01-22 - Wzl - modified to use clsSettingsAPI for storing position
| |
− | | |
− | Implements clsSettingAPI
| |
− | | |
− | Public WithEvents Form As Form
| |
− | Public doSaveSize As Boolean
| |
− | Public doAutoSave As Boolean
| |
− | | |
− | Private strPos As String
| |
− | 'Private objSet As clsSettingsNodeAPI
| |
− | Private strName As String
| |
− | | |
− | Option Explicit
| |
− | Public Sub Init(iForm As Form)
| |
− | Set Form = iForm
| |
− | doSaveSize = (iForm.BorderStyle = vbSizable) Or (iForm.BorderStyle = vbSizableToolWindow)
| |
− | ' Set objSet = iSettings
| |
− | ' Me.LoadPos
| |
− | strName = iForm.Name
| |
− | End Sub
| |
− | Public Property Let Pos(istr As String)
| |
− | strPos = istr
| |
− | If Me.Form.Visible Then Me.PlaceForm
| |
− | End Property
| |
− | Public Property Get Pos() As String
| |
− | ' ACTION: return a string specifying the given form's size and position
| |
− | Dim ostr As String
| |
− | Dim can_size As Boolean
| |
− |
| |
− | With Me.Form
| |
− | If .WindowState <> vbNormal Then
| |
− | .WindowState = vbNormal ' so dimensions are meaningful when we read them
| |
− | End If
| |
− | ostr = .Left & " " & .Top
| |
− | If doSaveSize Then
| |
− | ostr = ostr & " " & .Width & " " & .Height
| |
− | End If
| |
− | End With
| |
− | Pos = ostr
| |
− | End Property
| |
− | 'Public Sub Reveal()
| |
− | '' ACTION: show the given form, and make sure it's not minimized.
| |
− | ' With Me.Form
| |
− | ' .Show
| |
− | ' If .WindowState = vbMinimized Then
| |
− | ' .WindowState = vbNormal
| |
− | ' End If
| |
− | ' LoadPos ' restore saved position
| |
− | ' End With
| |
− | 'End Sub
| |
− | 'Public Sub LoadPos(Optional iKey As String)
| |
− | ' If iKey = "" Then
| |
− | ' iKey = Form.Name
| |
− | ' End If
| |
− | ' Me.Pos = objSet.Value(iKey)
| |
− | ' PlaceForm
| |
− | 'End Sub
| |
− | 'Public Sub SavePos(Optional iKey As String)
| |
− | '' PURPOSE: saves the given form's position to the registry
| |
− | ' With Me.Form
| |
− | ' If iKey = "" Then
| |
− | ' iKey = .Name
| |
− | ' End If
| |
− | ' If .Visible And (.WindowState <> vbMinimized) Then
| |
− | ' objSet.Value(iKey) = Me.Pos
| |
− | ' End If
| |
− | ' End With
| |
− | 'End Sub
| |
− | Public Sub PlaceForm()
| |
− | ' ACTION: set the given form's size and position from the stored string
| |
− | Dim oarr As Variant
| |
− | Dim can_size As Boolean
| |
− |
| |
− | If strPos = "" Then
| |
− | ' use default position: center in screen
| |
− | With Me.Form
| |
− | .Left = (Screen.Width - .Width) / 2
| |
− | .Top = (Screen.Height - .Height) / 2
| |
− | End With
| |
− | Else
| |
− | ' use stored position (and size if applicable)
| |
− | oarr = Split(strPos, " ")
| |
− | With Form
| |
− | .Left = oarr(0)
| |
− | .Top = oarr(1)
| |
− | If .Left > Screen.Width Then
| |
− | .Left = Screen.Width - .Width
| |
− | End If
| |
− | If .Top > Screen.Height Then
| |
− | .Top = Screen.Height - .Height
| |
− | End If
| |
− | If doSaveSize And (UBound(oarr) > 1) Then
| |
− | .Width = oarr(2)
| |
− | .Height = oarr(3)
| |
− | End If
| |
− | End With
| |
− | End If
| |
− | End Sub
| |
− | Private Sub clsSettingAPI_Load(iNode As clsSettingsNodeAPI)
| |
− | strPos = iNode.ValueStored
| |
− | PlaceForm
| |
− | End Sub
| |
− | Private Property Let clsSettingAPI_Name(ByVal RHS As String)
| |
− | strName = RHS
| |
− | End Property
| |
− | Private Property Get clsSettingAPI_Name() As String
| |
− | clsSettingAPI_Name = strName
| |
− | End Property
| |
− | Private Sub clsSettingAPI_Save(iNode As clsSettingsNodeAPI)
| |
− | iNode.ValueStored = Me.Pos
| |
− | End Sub
| |
− | Private Property Let clsSettingAPI_Value(ByVal RHS As String)
| |
− | strPos = RHS
| |
− | PlaceForm
| |
− | End Property
| |
− | Private Property Get clsSettingAPI_Value() As String
| |
− | clsSettingAPI_Value = Me.Pos
| |
− | End Property
| |
− | 'Private Sub Form_Activate()
| |
− | ' EVENT: runs the first time the form is shown
| |
− | ' Me.PlaceForm
| |
− | 'End Sub
| |
− | Private Sub Form_Deactivate()
| |
− | strPos = Me.Pos ' get new position
| |
− | End Sub
| |
− | Private Sub Form_QueryUnload(Cancel As Integer, UnloadMode As Integer)
| |
− | ' This is redundant; xtForm also handles this
| |
− | ' If doAutoSave Then
| |
− | ' Me.SavePos
| |
− | ' End If
| |
− | End Sub
| |
− | </pre>
| |
− | ===xtListBox===
| |
− | Implementation of [[#clsSettingAPI]]
| |
− | <pre>
| |
− | ' CLASS: xtListBox
| |
− | ' PURPOSE: extended functionality for ListBox control
| |
− | ' REQUIRES: xtListItems.cls, xtListItem.cls, property let/get AppSetting(Name)
| |
− | Option Explicit
| |
− | Implements clsSettingAPI
| |
− | | |
− | Public Event ItemChosen(oKey As Long)
| |
− | Public Event ItemChecked(oKey As Long)
| |
− | | |
− | 'Public Config As clsSettingsNodeAPI
| |
− | | |
− | 'local variable(s) to hold property value(s)
| |
− | Private strName As String
| |
− | Private WithEvents ctrlList As ListBox 'local copy
| |
− | Private WithEvents ctrlForm As Form
| |
− | Private lstItems As Scripting.Dictionary
| |
− | Private doDataSave As Boolean
| |
− | Private intNewItem As Long
| |
− | Public Sub Init(iList As ListBox, Optional iDataSave As Boolean = True)
| |
− | Set ctrlList = iList
| |
− | Set ctrlForm = iList.Parent
| |
− | ' Set Config = iConfig
| |
− | Set lstItems = New Scripting.Dictionary
| |
− | doDataSave = iDataSave
| |
− | With ctrlList
| |
− | strName = .Parent.Name & "." & .Name
| |
− | End With
| |
− | End Sub
| |
− | Public Property Get List() As Scripting.Dictionary
| |
− | Set List = lstItems
| |
− | End Property
| |
− | Public Sub Add(iText As String, Optional iObj As Object)
| |
− | ' NOTES:
| |
− | ' 1. Add object to list
| |
− | ' 2. Add text to listbox, with ItemData pointer to list
| |
− | With ctrlList
| |
− | intNewItem = intNewItem + 1
| |
− | .AddItem iText
| |
− | .ItemData(.NewIndex) = intNewItem
| |
− | lstItems.Add intNewItem, iObj
| |
− | End With
| |
− | End Sub
| |
− | Public Sub Clear()
| |
− | ctrlList.Clear
| |
− | lstItems.RemoveAll
| |
− | End Sub
| |
− | Public Property Get SelectedItem() As Object
| |
− | ' to be written
| |
− | End Property
| |
− | Public Function SelectCount() As Integer
| |
− | SelectCount = ctrlList.SelCount
| |
− | End Function
| |
− | Public Sub ClearSelection()
| |
− | ' PURPOSE: removes any selections from the control
| |
− | Dim idxList As Long, qtyList As Long
| |
− |
| |
− | qtyList = ctrlList.ListCount
| |
− | For idxList = 1 To qtyList
| |
− | ctrlList.Selected(idxList) = False
| |
− | Next
| |
− | End Sub
| |
− | Public Sub DelSelected()
| |
− | ' ACTION: Delete selected items from the list
| |
− | Dim idxList As Long, qtyList As Long
| |
− | Dim idxDel As Long
| |
− |
| |
− | qtyList = Me.List.Count
| |
− | For idxList = qtyList - 1 To 0 Step -1
| |
− | ' find the item's key in the stored list
| |
− | idxDel = lstItems.Keys(idxList)
| |
− | If ctrlList.Selected(idxList) Then
| |
− | ' delete item from the stored list
| |
− | lstItems.Remove idxDel
| |
− | ' delete item from the control
| |
− | ctrlList.RemoveItem idxList
| |
− | End If
| |
− | Next
| |
− | End Sub
| |
− | Public Sub KeyDown(KeyCode As Integer, Shift As Integer)
| |
− | '' PURPOSE: define additional standard behavior for non-ASCII key presses
| |
− | '' ACTION: Shift-Insert copies list contents to clipboard
| |
− | ' If ((KeyCode = vbKeyInsert) And (Shift & &H1)) Then
| |
− | ' ClipCopy
| |
− | ' End If
| |
− | End Sub
| |
− | Private Sub clsSettingAPI_Load(iNode As clsSettingsNodeAPI)
| |
− | ' ACTION: Load current selection and, if applicable, list data
| |
− | Dim qtyItem As Long
| |
− | Dim idxItem As Long
| |
− | Dim objNode As clsSettingsNodeAPI
| |
− | Dim strVal As String
| |
− |
| |
− | ' Me.Value = iNode.ValueStored
| |
− | ' check for saved data list
| |
− | qtyItem = iNode.ListNodes.Count
| |
− | ' load data, if there is any
| |
− | For idxItem = 0 To qtyItem - 1
| |
− | Set objNode = iNode.ListNodes.Items(idxItem)
| |
− | strVal = objNode.ValueStored
| |
− | If objNode.Name = "selected" Then
| |
− | Me.Value = objNode.ValueStored
| |
− | Else
| |
− | If strVal <> "" Then
| |
− | ' klugefix
| |
− | If Not Me.List.Exists(strVal) Then
| |
− | Me.Add strVal
| |
− | End If
| |
− | End If
| |
− | End If
| |
− | Next
| |
− | End Sub
| |
− | Private Property Let clsSettingAPI_Name(ByVal RHS As String)
| |
− | strName = RHS
| |
− | End Property
| |
− | Private Property Get clsSettingAPI_Name() As String
| |
− | clsSettingAPI_Name = strName
| |
− | End Property
| |
− | Private Sub clsSettingAPI_Save(iNode As clsSettingsNodeAPI)
| |
− | Dim idxItem As Long
| |
− | Dim objNode As clsSettingsNodeAPI
| |
− |
| |
− | Set objNode = iNode.Node("selected", True)
| |
− | objNode.ValueStored = Me.Value
| |
− | If doDataSave Then
| |
− | For idxItem = 0 To Me.List.Count - 1
| |
− | Set objNode = iNode.Node("line-" & CStr(idxItem), True)
| |
− | objNode.ValueStored = ctrlList.List(idxItem)
| |
− | Next
| |
− | End If
| |
− | End Sub
| |
− | Public Property Let Value(iValue As String)
| |
− | Dim xtsVal As xtString
| |
− | Dim idxSel As Long
| |
− | Dim strSel As String
| |
− |
| |
− | Set xtsVal = New xtString
| |
− |
| |
− | xtsVal.Value = iValue ' data is list of selected items, by index
| |
− | ' parse data
| |
− | strSel = xtsVal.FindFirst
| |
− | Do While xtsVal.IsFound
| |
− | If IsNumeric(strSel) Then
| |
− | idxSel = CLng(strSel)
| |
− | ctrlList.Selected(idxSel) = True
| |
− | End If
| |
− | strSel = xtsVal.FindNext
| |
− | Loop
| |
− | End Property
| |
− | Public Property Get Value() As String
| |
− | Dim strSel As String
| |
− | Dim idxItem As Long
| |
− |
| |
− | ' debugging:
| |
− | ' If Me.List.Count <> ctrlList.ListCount Then Stop
| |
− | | |
− | For idxItem = 0 To ctrlList.ListCount - 1
| |
− | If ctrlList.Selected(idxItem) Then
| |
− | strSel = strSel & " " & idxItem
| |
− | End If
| |
− | Next
| |
− | Value = strSel
| |
− | End Property
| |
− | Private Property Let clsSettingAPI_Value(ByVal RHS As String)
| |
− | Me.Value = RHS
| |
− | End Property
| |
− | Private Property Get clsSettingAPI_Value() As String
| |
− | clsSettingAPI_Value = Me.Value
| |
− | End Property
| |
− | Private Sub ctrlList_Click()
| |
− | Dim intLine As Integer
| |
− | Dim intKey As Long
| |
− | | |
− | intLine = ctrlList.ListIndex
| |
− | intKey = ctrlList.ItemData(intLine)
| |
− | If intKey Then
| |
− | RaiseEvent ItemChosen(intKey)
| |
− | End If
| |
− | End Sub
| |
− | Private Sub ctrlList_ItemCheck(Item As Integer)
| |
− | Dim intKey As Long
| |
− | | |
− | If Me.List.Exists(Item) Then
| |
− | intKey = ctrlList.ItemData(Item)
| |
− | RaiseEvent ItemChecked(intKey)
| |
− | End If
| |
− | End Sub
| |
− | </pre>
| |