From 3313a8fb89c63ffea2c1b9f6b63e0d85561e9a47 Mon Sep 17 00:00:00 2001 From: IRBorisov <8611739+IRBorisov@users.noreply.github.com> Date: Fri, 7 Jun 2024 20:14:51 +0300 Subject: [PATCH] Initial commit --- VBAMake.txt | 31 +++++++++ script/decisionsManagement.txt | 60 +++++++++++++++++ skeleton/!Управление решениями.xlsm | Bin 0 -> 42708 bytes src/DataAccess.bas | 62 ++++++++++++++++++ src/Declarations.bas | 47 ++++++++++++++ src/DevHelper.bas | 23 +++++++ src/FileScaner.cls | 97 ++++++++++++++++++++++++++++ src/Main.bas | 20 ++++++ src/MainImpl.bas | 30 +++++++++ src/s_DataAccess.cls | 71 ++++++++++++++++++++ src/s_FileScaner.cls | 78 ++++++++++++++++++++++ 11 files changed, 519 insertions(+) create mode 100644 VBAMake.txt create mode 100644 script/decisionsManagement.txt create mode 100644 skeleton/!Управление решениями.xlsm create mode 100644 src/DataAccess.bas create mode 100644 src/Declarations.bas create mode 100644 src/DevHelper.bas create mode 100644 src/FileScaner.cls create mode 100644 src/Main.bas create mode 100644 src/MainImpl.bas create mode 100644 src/s_DataAccess.cls create mode 100644 src/s_FileScaner.cls diff --git a/VBAMake.txt b/VBAMake.txt new file mode 100644 index 0000000..5dfc8e9 --- /dev/null +++ b/VBAMake.txt @@ -0,0 +1,31 @@ +# == Properties Section == +# configuration properties +# use .ini format to define properties +# mandatory properties: name, artifact_home, source_home + +id = Concept-Tasks +name = Концепт-Задачи +description = Технология управления решениями и задачами +artifact_home = Концепт-Задачи +source_home = Concept-Tasks +install_home = \\fs1.concept.ru\projects\10 Автоматизация деятельности\01 Высокие технологии\Концепт-Задачи + +%% +# === Build section === +# Available commands: +# build LOCAL_MANIFEST +# copy LOCAL_SOURCE -> [LOCAL_ARTIFACT] +# save_as LOCAL_ARTIFACT -> LOCAL_ARTIFACT +# run LOCAL_SOURCE.bat + +build script\decisionsManagement.txt + +%% +# === Install section == +# Available commands: +# install LOCAL_ARTIFACT -> [INSTALL_PATH] +# add_template LOCAL_ARTIFACT -> [LOCAL_TEMPLATE] +# run LOCAL_ARTIFACT.bat <- [PARAMETERS] +# run APPLICATION <- [PARAMETERS] + +install !Управление решениями.xlsm \ No newline at end of file diff --git a/script/decisionsManagement.txt b/script/decisionsManagement.txt new file mode 100644 index 0000000..9702612 --- /dev/null +++ b/script/decisionsManagement.txt @@ -0,0 +1,60 @@ +# == Properties Section == +# configuration properties +# use .ini format to define properties +# mandatory properties: name, artifact + +name = !Управление решениями.xlsm +artifact = !Управление решениями.xlsm + +%% +# === Imports Section === +# Hierarchy of folders and files +# Use Tabulator to mark next level in hierarchy +# All folders are nested into SharedHome path + +dev + DevTester.bas + +api + API_WordWrapper.cls + API_XLWrapper.cls + +utility + ex_DataPreparation.bas + ex_VBA.bas + +%% +# === Source Code Section == +# Hierarchy of folders and files +# Use Tabulator to mark next level in hierarchy +# All folders are nested into SourceHome path + +src + DevHelper.bas + Declarations.bas + DataAccess.bas + Main.bas + MainImpl.bas + + FileScaner.cls + s_DataAccess.cls + s_FileScaner.cls + +%% +# ===== UI Section ======= +# Pairs of path to UI elements, use " -> " delimiter +# First component is a path relative to SourceHome\ui folders +# Second component is internal path inside project file + + + +%% +# === References Section === +# List dependencies in one of the formats +# global : GLOBAL_NAME +# guid : {REGISTERED_GUID} +# file : PATH_TO_LIBRARY + +global : Scripting +global : Word +global : MSForms \ No newline at end of file diff --git a/skeleton/!Управление решениями.xlsm b/skeleton/!Управление решениями.xlsm new file mode 100644 index 0000000000000000000000000000000000000000..e223673fcfc2e3a8daf1867af260335094f6289b GIT binary patch literal 42708 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 vbNullString + Dim sFile$: sFile = wData.Cells(nRow, S_SRC_FILE).Text + If Not Sources.Exists(sFile) Then _ + Call Sources.Add(sFile, wData.Cells(nRow, S_SRC_ID)) + nRow = nRow + 1 + Loop +End Function + +Public Function SourceLocations() As Collection + Set SourceLocations = New Collection + + Dim tData As Excel.ListObject: Set tData = ThisWorkbook.Worksheets(SHEET_PARAMS).ListObjects(TABLE_SOURCE_LOCATIONS) + Dim dataRng As Excel.Range: Set dataRng = tData.Range + Dim nRow&: nRow = FIRST_ROW + For nRow = FIRST_ROW To dataRng.Rows.Count Step 1 + If dataRng.Cells(nRow, 1) <> vbNullString Then _ + Call SourceLocations.Add(dataRng.Cells(nRow, 1).Text) + Next nRow +End Function + +Public Function AddSource(sProject$, sFile$) As Long + If sFile = vbNullString Then _ + Exit Function + + Dim wData As Excel.Worksheet: Set wData = ThisWorkbook.Sheets(SHEET_SOURCES) + Dim nRow&: nRow = FIRST_ROW + Do While wData.Cells(nRow, S_SRC_ID) <> vbNullString + nRow = nRow + 1 + Loop + AddSource = Application.WorksheetFunction.Max(wData.Columns(S_SRC_ID)) + 1 + wData.Cells(nRow, S_SRC_ID) = AddSource + wData.Cells(nRow, S_SRC_PROJECT) = sProject + wData.Cells(nRow, S_SRC_FILE) = sFile + Dim hRange As Excel.Range: Set hRange = wData.Cells(nRow, S_SRC_FILE) + Call hRange.Hyperlinks.Add(hRange, sFile) +End Function + +Public Function AddTask(dDate As Double, sProject$, sText$, sResponsible$, nSource&, sFile$) As Long + Dim wData As Excel.Worksheet: Set wData = ThisWorkbook.Sheets(SHEET_TASKS) + Dim nRow&: nRow = FIRST_ROW + Call wData.Rows(nRow).EntireRow.Insert(Shift:=xlShiftDown, CopyOrigin:=xlFormatFromRightOrBelow) + + AddTask = Application.WorksheetFunction.Max(wData.Columns(S_TASK_ID)) + 1 + wData.Cells(nRow, S_TASK_ID) = AddTask + wData.Cells(nRow, S_TASK_STATUS) = T_TT_OPEN + wData.Cells(nRow, S_TASK_PROJECT) = sProject + wData.Cells(nRow, S_TASK_TEXT) = sText + wData.Cells(nRow, S_TASK_RESPONSIBLE) = sResponsible + wData.Cells(nRow, S_TASK_SOURCE_ID) = nSource + wData.Cells(nRow, S_TASK_DATE) = IIf(dDate = 0, "", dDate) + + Dim hRange As Excel.Range: Set hRange = wData.Cells(nRow, S_TASK_SOURCE_ID) + Call hRange.Hyperlinks.Add(hRange, sFile) +End Function diff --git a/src/Declarations.bas b/src/Declarations.bas new file mode 100644 index 0000000..dddea88 --- /dev/null +++ b/src/Declarations.bas @@ -0,0 +1,47 @@ +Attribute VB_Name = "Declarations" +Option Private Module +Option Explicit + +Public Const SHEET_SOURCES = "" +Public Const SHEET_TASKS = "" +Public Const SHEET_PARAMS = "" + +Public Const TABLE_SOURCE_LOCATIONS = "t_SourceLocations" +Public Const TABLE_STATUSES = "t_Status" + +Public Const WORD_MASK = "*.doc*" + +Public Const FIRST_ROW = 2 + +' Task type +Public Enum TTaskType + T_TT_OPEN = 0 + T_TT_CLOSED = 1 + T_TT_CANCELED = 2 +End Enum + +' _SRC_ - Source structure +Public Enum SourceStruct + [_First] = 1 + + S_SRC_ID = 1 + S_SRC_PROJECT = 2 + S_SRC_FILE = 3 + + [_Last] = 3 +End Enum + +' _TASK_ - Task structure +Public Enum TaskStruct + [_First] = 1 + + S_TASK_ID = 1 + S_TASK_DATE = 2 + S_TASK_PROJECT = 3 + S_TASK_STATUS = 4 + S_TASK_TEXT = 5 + S_TASK_RESPONSIBLE = 6 + S_TASK_SOURCE_ID = 7 + + [_Last] = 7 +End Enum diff --git a/src/DevHelper.bas b/src/DevHelper.bas new file mode 100644 index 0000000..0d43d72 --- /dev/null +++ b/src/DevHelper.bas @@ -0,0 +1,23 @@ +Attribute VB_Name = "DevHelper" +Option Private Module +Option Explicit + +Public Function Dev_PrepareSkeleton() + ' Do nothing + ClearAll +End Function + +Public Function Dev_ManualRunTest() + Dim sSuite$: sSuite = "s_FileScaner" + Dim sTest$: sTest = "t_ScanContents" + Dim sMsg$: sMsg = Dev_RunTestDebug(sSuite, sTest) + Debug.Print sMsg + Call MsgBox(sMsg) +End Function + +Public Function Dev_GetTestSuite(sName$) As Object + Select Case sName + Case "s_FileScaner": Set Dev_GetTestSuite = New s_FileScaner + Case "s_DataAccess": Set Dev_GetTestSuite = New s_DataAccess + End Select +End Function diff --git a/src/FileScaner.cls b/src/FileScaner.cls new file mode 100644 index 0000000..b90a84f --- /dev/null +++ b/src/FileScaner.cls @@ -0,0 +1,97 @@ +VERSION 1.0 CLASS +BEGIN + MultiUse = -1 'True +END +Attribute VB_Name = "FileScaner" +Attribute VB_GlobalNameSpace = False +Attribute VB_Creatable = False +Attribute VB_PredeclaredId = False +Attribute VB_Exposed = False +Option Explicit + +Private word_ As API_WordWrapper +Private doc_ As Word.Document + +Public Function Init() + Set word_ = New API_WordWrapper + Call word_.CreateApplication(bIsVisible:=True) +End Function + +Public Function Finalize() + Call word_.ReleaseApplication + Set word_ = Nothing +End Function + +Public Function Process(sFile$) As Long + If word_.OpenDocument(sFile, bReadOnly:=True) Is Nothing Then _ + Exit Function + + Process = ProcessDocument(word_.Document) + + Call word_.ReleaseDocument(bCloseApplication:=False) +End Function + +Public Function ProcessDocument(target As Word.Document) As Long + Set doc_ = target + + Dim sProject$: sProject = ExtractProject + Dim dDate As Double: dDate = ExtractDate + + Dim nSourceID&: nSourceID = AddSource(sProject, doc_.FullName) + ProcessDocument = ProcessTasks(dDate, sProject, nSourceID) + + Set doc_ = Nothing +End Function + +' ======= +Private Function ProcessTasks(dDate As Double, sProject$, nSourceID&) As Long + Dim taskRange As Word.Range: Set taskRange = doc_.Range + With taskRange.Find + .Text = ":" + .MatchCase = True + If Not .Execute Then _ + Exit Function + End With + + taskRange.Start = taskRange.End + 2 + taskRange.End = doc_.Range.End + + Dim aPara As Word.Paragraph + Dim nPara + For nPara = taskRange.Paragraphs.Count To 1 Step -1 + Set aPara = taskRange.Paragraphs(nPara) + Dim sText$: sText = SubstituteWhitespace(aPara.Range.Text) + If sText <> vbNullString Then + If AddTaskInternal(sText, dDate, sProject, nSourceID, doc_.FullName) Then _ + ProcessTasks = ProcessTasks + 1 + End If + Next nPara +End Function + +Private Function AddTaskInternal(ByRef sText$, dDate As Double, sProject$, nSourceID&, sFile$) As Boolean + AddTaskInternal = False + + Dim nDelim&: nDelim = VBA.InStrRev(sText, "@@") + If nDelim = 0 Then _ + Exit Function + + Dim sResponsible$: sResponsible = VBA.Right(sText, VBA.Len(sText) - nDelim - 1) + sText = VBA.Left(sText, VBA.Len(sText) - VBA.Len(sResponsible) - 2) + sText = TrimEndPunctuation(sText) + Call AddTask(dDate, sProject, VBA.Trim(sText), VBA.Trim(sResponsible), nSourceID, sFile) + + AddTaskInternal = True +End Function + +Private Function ExtractProject() As String + On Error Resume Next + ExtractProject = TrimWhitespace(doc_.Tables(1).Cell(1, 3).Range.Text) +End Function + +Private Function ExtractDate() As Double + On Error Resume Next + Dim sDate$: sDate = TrimWhitespace(doc_.Tables(1).Cell(3, 2).Range.Text) + If Len(sDate) <= 2 Then _ + Exit Function + ExtractDate = DateValue(sDate) +End Function diff --git a/src/Main.bas b/src/Main.bas new file mode 100644 index 0000000..158da87 --- /dev/null +++ b/src/Main.bas @@ -0,0 +1,20 @@ +Attribute VB_Name = "Main" +Option Explicit + +Public Sub RunUpdate() + Dim oLocations As Collection: Set oLocations = SourceLocations + Dim knownSources As Scripting.Dictionary: Set knownSources = Sources + + Dim xlUI As New API_XLWrapper: Call xlUI.SetDocument(ThisWorkbook) + Call xlUI.PauseUI + + Dim aLocation As Variant + Dim nCount&: nCount = 0 + For Each aLocation In oLocations + nCount = nCount + ImportDataFrom(CStr(aLocation), knownSources) + Next aLocation + + Call xlUI.ResumeUI + + Call MsgBox(Fmt(" : {1}", nCount), vbInformation) +End Sub diff --git a/src/MainImpl.bas b/src/MainImpl.bas new file mode 100644 index 0000000..ad6719e --- /dev/null +++ b/src/MainImpl.bas @@ -0,0 +1,30 @@ +Attribute VB_Name = "MainImpl" +Option Private Module +Option Explicit + +Public Function ClearAll() + Call ThisWorkbook.Sheets(SHEET_SOURCES).UsedRange.Offset(1, 0).ClearContents + Call ThisWorkbook.Sheets(SHEET_TASKS).UsedRange.Offset(1, 0).ClearContents +End Function + +Public Function ImportDataFrom(sFolder$, knownSources As Scripting.Dictionary) As Long + Dim oFiles As Collection: Set oFiles = ListFiles(sFolder, WORD_MASK) + Dim sFile As Variant + Dim iScaner As New FileScaner: Call iScaner.Init + For Each sFile In oFiles + Dim sFullPath$: sFullPath = sFolder & "\" & CStr(sFile) + If Not knownSources.Exists(sFullPath) Then _ + ImportDataFrom = ImportDataFrom + iScaner.Process(sFullPath) + Next sFile + Call iScaner.Finalize +End Function + +' ==== +Private Function ListFiles(sFolder$, sMask$) As Collection + Set ListFiles = New Collection + Dim sFile$: sFile = Dir(sFolder & "\" & sMask) + Do While Len(sFile) > 0 And sFile <> sFolder + Call ListFiles.Add(sFile) + sFile = Dir + Loop +End Function diff --git a/src/s_DataAccess.cls b/src/s_DataAccess.cls new file mode 100644 index 0000000..d95823b --- /dev/null +++ b/src/s_DataAccess.cls @@ -0,0 +1,71 @@ +VERSION 1.0 CLASS +BEGIN + MultiUse = -1 'True +END +Attribute VB_Name = "s_DataAccess" +Attribute VB_GlobalNameSpace = False +Attribute VB_Creatable = False +Attribute VB_PredeclaredId = False +Attribute VB_Exposed = False +Option Explicit + +Public Function Setup() + ' Mandatory setup function +End Function + +Public Function Teardown() + ' Mandatory teardown function + Call ClearAll +End Function + +Public Function t_Sources() + On Error GoTo PROPAGATE_ERROR + + Call Dev_ExpectEQ(CSet(), Sources(), "Empty data") + Call Dev_ExpectEQ(0, AddSource("proj1", ""), "Empty file") + + Dim iSources As New Scripting.Dictionary + iSources("C:\Windows\file1.docx") = 1 + iSources("invalid path?") = 2 + iSources("C:\Windows\file2.docx") = 3 + + Call Dev_ExpectEQ(1, AddSource("proj1", "C:\Windows\file1.docx"), "Add valid path") + Call Dev_ExpectEQ(2, AddSource("proj1", "invalid path?"), "Add invalid path") + Call Dev_ExpectEQ(3, AddSource("", "C:\Windows\file2.docx"), "Empty project") + Call Dev_ExpectEQ(4, AddSource("proj2", "C:\Windows\file1.docx"), "Duplicate file") + Call Dev_ExpectEQ(iSources, Sources(), "Valid data") + Dim iCell As Excel.Range: Set iCell = ThisWorkbook.Sheets(SHEET_SOURCES).Cells(FIRST_ROW, S_SRC_FILE) + Call Dev_ExpectEQ("C:\Windows\file1.docx", iCell.Hyperlinks(1).Address, "Add hyperlink") + + Call Dev_NewCase("Custom id") + ThisWorkbook.Sheets(SHEET_SOURCES).Cells(FIRST_ROW, S_SRC_ID) = 100 + Call Dev_ExpectEQ(101, AddSource("proj3", "C:\Windows\file6.docx")) + + Exit Function +PROPAGATE_ERROR: + Call Dev_LogError(Err.Number, Err.Description) +End Function + +Public Function t_Tasks() + On Error GoTo PROPAGATE_ERROR + + Dim iTasks As Excel.Worksheet: Set iTasks = ThisWorkbook.Sheets(SHEET_TASKS) + + Call Dev_NewCase("Valid add task") + Call Dev_ExpectEQ(1, AddTask(100, "project", "text", "resp", 1337, "C:\Windows\file1.docx")) + Call Dev_ExpectEQ(1, iTasks.Cells(FIRST_ROW, S_TASK_ID)) + Call Dev_ExpectEQ(100, iTasks.Cells(FIRST_ROW, S_TASK_DATE)) + Call Dev_ExpectEQ(T_TT_OPEN, iTasks.Cells(FIRST_ROW, S_TASK_STATUS)) + Call Dev_ExpectEQ("project", iTasks.Cells(FIRST_ROW, S_TASK_PROJECT)) + Call Dev_ExpectEQ("text", iTasks.Cells(FIRST_ROW, S_TASK_TEXT)) + Call Dev_ExpectEQ("resp", iTasks.Cells(FIRST_ROW, S_TASK_RESPONSIBLE)) + Call Dev_ExpectEQ(1337, iTasks.Cells(FIRST_ROW, S_TASK_SOURCE_ID)) + + Call Dev_NewCase("Insert new to top") + Call Dev_ExpectEQ(2, AddTask(101, "project2", "text2", "resp2", 13373, "C:\Windows\file2.docx")) + Call Dev_ExpectEQ(2, iTasks.Cells(FIRST_ROW, S_TASK_ID)) + + Exit Function +PROPAGATE_ERROR: + Call Dev_LogError(Err.Number, Err.Description) +End Function diff --git a/src/s_FileScaner.cls b/src/s_FileScaner.cls new file mode 100644 index 0000000..3907e5c --- /dev/null +++ b/src/s_FileScaner.cls @@ -0,0 +1,78 @@ +VERSION 1.0 CLASS +BEGIN + MultiUse = -1 'True +END +Attribute VB_Name = "s_FileScaner" +Attribute VB_GlobalNameSpace = False +Attribute VB_Creatable = False +Attribute VB_PredeclaredId = False +Attribute VB_Exposed = False +Option Explicit + +Private iScaner_ As FileScaner +Private word_ As API_WordWrapper +Private doc_ As Word.Document + +Public Function Setup() + ' Mandatory setup function + Set word_ = New API_WordWrapper: Call word_.CreateApplication + Set doc_ = word_.NewDocument + Set iScaner_ = New FileScaner +End Function + +Public Function Teardown() + ' Mandatory teardown function + Call word_.ReleaseDocument + Call ClearAll +End Function + +Public Function t_EmptyFile() + On Error GoTo PROPAGATE_ERROR + + Call Dev_ExpectEQ(0, iScaner_.ProcessDocument(doc_), "Do not scan tasks") + Call Dev_ExpectEQ(1, Sources().Count, "Add source") + + Exit Function +PROPAGATE_ERROR: + Call Dev_LogError(Err.Number, Err.Description) +End Function + +Public Function t_ScanContents() + On Error GoTo PROPAGATE_ERROR + + Dim iTasks As Excel.Worksheet: Set iTasks = ThisWorkbook.Sheets(SHEET_TASKS) + + Dim iTable As Word.Table: Set iTable = doc_.Tables.Add(doc_.Range, 3, 3) + iTable.Cell(1, 3).Range.Text = "Project" + iTable.Cell(3, 2).Range.Text = "2005-01-12" + Dim dDate As Double: dDate = VBA.DateValue("2005-01-12") + + Call doc_.Range.InsertAfter(":" & vbNewLine) + Call doc_.Range.InsertAfter("Task 1@@" & vbNewLine) + Call doc_.Range.InsertAfter("Task 2 @@Person") + + Call Dev_ExpectEQ(2, iScaner_.ProcessDocument(doc_), "Task count") + Call Dev_ExpectEQ(1, Sources().Count, "Add source") + + Call Dev_NewCase("Task without responsible") + Call Dev_ExpectEQ(2, iTasks.Cells(FIRST_ROW, S_TASK_ID)) + Call Dev_ExpectEQ(dDate, iTasks.Cells(FIRST_ROW, S_TASK_DATE)) + Call Dev_ExpectEQ(T_TT_OPEN, iTasks.Cells(FIRST_ROW, S_TASK_STATUS)) + Call Dev_ExpectEQ("Project", iTasks.Cells(FIRST_ROW, S_TASK_PROJECT)) + Call Dev_ExpectEQ("Task 1", iTasks.Cells(FIRST_ROW, S_TASK_TEXT)) + Call Dev_ExpectEQ("", iTasks.Cells(FIRST_ROW, S_TASK_RESPONSIBLE)) + Call Dev_ExpectEQ(1, iTasks.Cells(FIRST_ROW, S_TASK_SOURCE_ID)) + + Call Dev_NewCase("Task with responsible") + Call Dev_ExpectEQ(1, iTasks.Cells(FIRST_ROW + 1, S_TASK_ID)) + Call Dev_ExpectEQ(dDate, iTasks.Cells(FIRST_ROW + 1, S_TASK_DATE)) + Call Dev_ExpectEQ(T_TT_OPEN, iTasks.Cells(FIRST_ROW + 1, S_TASK_STATUS)) + Call Dev_ExpectEQ("Project", iTasks.Cells(FIRST_ROW + 1, S_TASK_PROJECT)) + Call Dev_ExpectEQ("Task 2", iTasks.Cells(FIRST_ROW + 1, S_TASK_TEXT)) + Call Dev_ExpectEQ("Person", iTasks.Cells(FIRST_ROW + 1, S_TASK_RESPONSIBLE)) + Call Dev_ExpectEQ(1, iTasks.Cells(FIRST_ROW + 1, S_TASK_SOURCE_ID)) + + Exit Function +PROPAGATE_ERROR: + Call Dev_LogError(Err.Number, Err.Description) +End Function