From 6bf2d43f9624a9ac18e94b5f8541bfc941cb13a3 Mon Sep 17 00:00:00 2001 From: Joshua Shoemaker Date: Sat, 2 Sep 2023 10:39:03 -0500 Subject: [PATCH] refact: context groups | feat: area detection and a bunch of small things. hate yourself for this massive commit --- .vscode/settings.json | 2 + core/ContextGroup/ContextGroupCollection.go | 35 ++++++ frontend/components/DocumentCanvas/Area.tsx | 23 +--- frontend/components/DocumentCanvas/Areas.tsx | 34 +++--- .../components/DocumentCanvas/CanvasStage.tsx | 13 ++- .../ContextConnections/ConnectionLines.tsx | 1 + .../CurrentDrawingConnection.tsx | 1 + .../ToolingOverlay/ToolToggleButton.tsx | 2 +- .../DocumentCanvas/ToolingOverlay/index.tsx | 57 +++++++++- .../workspace/Sidebar/AreaLineItem.tsx | 4 +- frontend/consts/index.ts | 7 ++ .../context/Project/makeDefaultProject.ts | 5 +- frontend/context/Project/provider.tsx | 1 + frontend/context/Project/types.ts | 3 +- frontend/tailwind.config.js | 3 + frontend/useCases/processImageArea.ts | 16 ++- frontend/useCases/processImageRect.ts | 103 ++++++++++++++++++ frontend/wailsjs/wailsjs/go/ipc/Channel.d.ts | 4 +- frontend/wailsjs/wailsjs/go/ipc/Channel.js | 4 + ipc/ContextGroup.go | 24 +++- ipc/ProcessedDocument.go | 21 ++-- 21 files changed, 292 insertions(+), 71 deletions(-) create mode 100644 frontend/consts/index.ts create mode 100644 frontend/useCases/processImageRect.ts diff --git a/.vscode/settings.json b/.vscode/settings.json index 97a35ac..b0ed334 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -3,10 +3,12 @@ "*.css": "tailwindcss" }, "cSpell.words": [ + "consts", "headlessui", "heroicons", "konva", "libretranslate", + "tailwindcss", "Tesseract", "Textualize", "wailsjs" diff --git a/core/ContextGroup/ContextGroupCollection.go b/core/ContextGroup/ContextGroupCollection.go index 57d17fd..dfd0417 100644 --- a/core/ContextGroup/ContextGroupCollection.go +++ b/core/ContextGroup/ContextGroupCollection.go @@ -32,6 +32,41 @@ func SetContextGroupCollectionBySerialized(serialized []entities.SerializedLinke return &newInstance } +func (collection *ContextGroupCollection) DoesGroupExistBetweenProcessedAreas(ancestorAreaId string, descendantAreaId string) bool { + ancestorGroup, _ := collection.FindGroupByLinkedProcessedAreaId(ancestorAreaId) + descendantGroup, _ := collection.FindGroupByLinkedProcessedAreaId(descendantAreaId) + + isAncestorInAnyInGroup := ancestorGroup != nil + isDescendantInAnyInGroup := descendantGroup != nil + areBothInAnyInGroup := isAncestorInAnyInGroup && isDescendantInAnyInGroup + areBothInSameGroup := false + if areBothInAnyInGroup { + areBothInSameGroup = ancestorGroup.Id == descendantGroup.Id + } + + return areBothInSameGroup +} + +func (collection *ContextGroupCollection) DisconnectProcessedAreas(ancestorAreaId string, descendantAreaId string) bool { + doesConnectionExist := collection.DoesGroupExistBetweenProcessedAreas(ancestorAreaId, descendantAreaId) + + if !doesConnectionExist { + return false + } + + ancestorGroup, _ := collection.FindGroupByLinkedProcessedAreaId(ancestorAreaId) + + wasRemoved := false + for i, group := range collection.Groups { + if group.Id == ancestorGroup.Id { + collection.Groups = append(collection.Groups[:i], collection.Groups[i+1:]...) + wasRemoved = true + break + } + } + return wasRemoved +} + func (collection *ContextGroupCollection) FindGroupById(id string) (*entities.LinkedAreaList, error) { found := false var foundGroup *entities.LinkedAreaList = nil diff --git a/frontend/components/DocumentCanvas/Area.tsx b/frontend/components/DocumentCanvas/Area.tsx index 31a7e17..86551ba 100644 --- a/frontend/components/DocumentCanvas/Area.tsx +++ b/frontend/components/DocumentCanvas/Area.tsx @@ -12,39 +12,22 @@ import { useStage } from './context/provider' type Props = { isActive: boolean, area: entities.Area, - setHoveredOverAreaIds: Function - setHoveredProcessedArea: Function } type coordinates = { x: number, y: number } const Area = (props: Props) => { - const { getProcessedAreaById, selectedAreaId, setSelectedAreaId } = useProject() + const { selectedAreaId, setSelectedAreaId } = useProject() const { scale } = useStage() const shapeRef = React.useRef(null) const [isAreaContextMenuOpen, setIsAreaContextMenuOpen] = useState(false) const [areaContextMenuPosition, setAreaContextMenuPosition] = useState() - const { area, isActive, setHoveredOverAreaIds, setHoveredProcessedArea } = props + const { area, isActive } = props const a = area const width = (a.endX - a.startX) const height = (a.endY - a.startY) - const handleEnterOrLeave = (e: KonvaEventObject) => { - const stage = e.currentTarget.getStage()! - const currentMousePosition = stage.pointerPos - const intersectingNodes = stage.getAllIntersections(currentMousePosition) - const drawnAreas = intersectingNodes.filter(n => n.attrs?.isArea) - const drawnAreasIds = drawnAreas.map(d => d.attrs?.id) - setHoveredOverAreaIds(drawnAreasIds) - - const processedAreaRequests = drawnAreasIds.map(a => getProcessedAreaById(a || '')) - Promise.all(processedAreaRequests).then(responses => { - const validResponses = responses.filter(r => r?.id) as entities.ProcessedArea[] - setHoveredProcessedArea(validResponses || []) - }) - } - const handleContextMenu = (e: KonvaEventObject) => { e.evt.preventDefault() const stage = e.currentTarget.getStage() @@ -76,8 +59,6 @@ const Area = (props: Props) => { strokeWidth={1} strokeScaleEnabled={false} shadowForStrokeEnabled={false} - onMouseEnter={handleEnterOrLeave} - onMouseLeave={handleEnterOrLeave} onClick={() => handleAreaClick(a.id)} onContextMenu={handleContextMenu} isArea diff --git a/frontend/components/DocumentCanvas/Areas.tsx b/frontend/components/DocumentCanvas/Areas.tsx index 39182af..2341711 100644 --- a/frontend/components/DocumentCanvas/Areas.tsx +++ b/frontend/components/DocumentCanvas/Areas.tsx @@ -1,6 +1,6 @@ 'use client' -import React, { useState } from 'react' +import React, { useEffect, useState } from 'react' import { Group } from 'react-konva' import { useProject } from '../../context/Project/provider' import { entities } from '../../wailsjs/wailsjs/go/models' @@ -12,12 +12,24 @@ import { useStage } from './context/provider' type Props = { scale: number } const Areas = ({ scale }: Props) => { - const { getSelectedDocument, selectedAreaId } = useProject() + const { getSelectedDocument, selectedAreaId, getProcessedAreaById } = useProject() const { isProcessedWordsVisible } = useStage() const areas = getSelectedDocument()?.areas || [] - const [hoveredOverAreaIds, setHoveredOverAreaIds] = useState([]) - const [hoveredProcessedAreas, setHoveredProcessedArea] = useState([]) const [editingWord, setEditingWord] = useState(null) + const [selectedProcessedArea, setSelectedProcessedArea] = useState(null) + + useEffect(() => { + if (!selectedAreaId) return setSelectedProcessedArea(null) + else { + getProcessedAreaById(selectedAreaId).then(res => { + if (res) setSelectedProcessedArea(res) + }).catch(err => { + console.warn('getProcessedAreaById', err) + setSelectedProcessedArea(null) + }) + } + + }, [selectedAreaId]) const renderEditingWord = () => { if (!editingWord) return @@ -29,26 +41,20 @@ const Areas = ({ scale }: Props) => { } const renderProcessedWords = () => { - if (!hoveredProcessedAreas.length) return + if (!selectedProcessedArea) return <> - return hoveredProcessedAreas.map(a => { - const words = a.lines.map(l => l.words).flat() + const words = selectedProcessedArea.lines.map(l => l.words).flat() return words.map((w, index) => ) - }) } const renderAreas = (areas: entities.Area[]) => areas.map((a, index) => { - return + return }) return diff --git a/frontend/components/DocumentCanvas/CanvasStage.tsx b/frontend/components/DocumentCanvas/CanvasStage.tsx index f0ef2e7..0be7910 100644 --- a/frontend/components/DocumentCanvas/CanvasStage.tsx +++ b/frontend/components/DocumentCanvas/CanvasStage.tsx @@ -9,15 +9,15 @@ import useImage from 'use-image' import { RectangleCoordinates } from './types' import DrawingArea from './DrawingArea' import getNormalizedRectToBounds from '../../utils/getNormalizedRectToBounds' -import processImageArea from '../../useCases/processImageArea' import { useStage } from './context/provider' import ContextConnections from './ContextConnections' +import processImageRect from '../../useCases/processImageRect' let downClickX: number let downClickY: number const CanvasStage = () => { - const { getSelectedDocument, requestAddArea, setSelectedAreaId } = useProject() + const { getSelectedDocument, updateDocuments, setSelectedAreaId } = useProject() const { scale, scaleStep, maxScale, size, setScale, isAreasVisible, isLinkAreaContextsVisible, isDrawingArea, setIsDrawingArea, startingContextConnection, setStartingContextConnection } = useStage() const [documentImage] = useImage(getSelectedDocument()?.path || '') const documentRef = useRef(null) @@ -55,11 +55,12 @@ const CanvasStage = () => { const normalizedDrawnRect = getNormalizedRectToBounds(drawingAreaRect, documentWidth, documentHeight, scale) const selectedDocumentId = getSelectedDocument()!.id - requestAddArea(selectedDocumentId, normalizedDrawnRect).then(addedArea => { - setSelectedAreaId(addedArea.id) - processImageArea(selectedDocumentId, addedArea.id) + processImageRect(selectedDocumentId, normalizedDrawnRect).then(async addedAreas => { + updateDocuments().then(response => { + if (!addedAreas.length) return + setSelectedAreaId(addedAreas[0].id) + }) }) - setDrawingAreaRect(null) } diff --git a/frontend/components/DocumentCanvas/ContextConnections/ConnectionLines.tsx b/frontend/components/DocumentCanvas/ContextConnections/ConnectionLines.tsx index 0b7c94e..c86ae84 100644 --- a/frontend/components/DocumentCanvas/ContextConnections/ConnectionLines.tsx +++ b/frontend/components/DocumentCanvas/ContextConnections/ConnectionLines.tsx @@ -60,6 +60,7 @@ const ConnectionLines = () => { strokeScaleEnabled={false} shadowForStrokeEnabled={false} tension={0.2} + listening={false} /> }) return lines.filter(l => !!l) diff --git a/frontend/components/DocumentCanvas/ContextConnections/CurrentDrawingConnection.tsx b/frontend/components/DocumentCanvas/ContextConnections/CurrentDrawingConnection.tsx index 0dd1568..550c727 100644 --- a/frontend/components/DocumentCanvas/ContextConnections/CurrentDrawingConnection.tsx +++ b/frontend/components/DocumentCanvas/ContextConnections/CurrentDrawingConnection.tsx @@ -50,6 +50,7 @@ const CurrentDrawingConnection = (props: CurrentDrawingConnectionProps) => { strokeScaleEnabled={false} shadowForStrokeEnabled={false} tension={0.2} + listening={false} /> } diff --git a/frontend/components/DocumentCanvas/ToolingOverlay/ToolToggleButton.tsx b/frontend/components/DocumentCanvas/ToolingOverlay/ToolToggleButton.tsx index d1f552d..08672a2 100644 --- a/frontend/components/DocumentCanvas/ToolingOverlay/ToolToggleButton.tsx +++ b/frontend/components/DocumentCanvas/ToolingOverlay/ToolToggleButton.tsx @@ -9,7 +9,7 @@ type Icon = (props: React.SVGProps & { }) => JSX.Element const ToolToggleButton = (props: { icon: Icon, hint: string, isActive: boolean, onClick?: React.MouseEventHandler }) => { - return
+ return
diff --git a/frontend/components/workspace/Sidebar/AreaLineItem.tsx b/frontend/components/workspace/Sidebar/AreaLineItem.tsx index 309f00b..efa7c3c 100644 --- a/frontend/components/workspace/Sidebar/AreaLineItem.tsx +++ b/frontend/components/workspace/Sidebar/AreaLineItem.tsx @@ -15,13 +15,13 @@ const AreaLineItem = (props: { area: SidebarArea, documentId: string, index: num getAreaById, requestUpdateArea, setSelectedDocumentId, - setSelectedAreaId, requestChangeAreaOrder, requestDeleteAreaById, + selectedAreaId, + setSelectedAreaId, } = useProject() const { - selectedAreaId, isEditAreaNameInputShowing, setIsEditAreaNameInputShowing, dragOverAreaId, diff --git a/frontend/consts/index.ts b/frontend/consts/index.ts new file mode 100644 index 0000000..5325b58 --- /dev/null +++ b/frontend/consts/index.ts @@ -0,0 +1,7 @@ +const colors = { + BRAND_PRIMARY: { + hex: '#dc8dec', + } +} + +export { colors } diff --git a/frontend/context/Project/makeDefaultProject.ts b/frontend/context/Project/makeDefaultProject.ts index 108b796..9295646 100644 --- a/frontend/context/Project/makeDefaultProject.ts +++ b/frontend/context/Project/makeDefaultProject.ts @@ -1,4 +1,4 @@ -import { entities } from '../../wailsjs/wailsjs/go/models' +import { entities, ipc } from '../../wailsjs/wailsjs/go/models' import { ProjectContextType, UserProps } from './types' const makeDefaultProject = (): ProjectContextType => ({ @@ -11,7 +11,7 @@ const makeDefaultProject = (): ProjectContextType => ({ getSelectedDocument: () => new entities.Document(), getAreaById: (areaId) => undefined, getProcessedAreasByDocumentId: (documentId) => Promise.resolve([new entities.ProcessedArea()]), - requestAddProcessedArea: (processesArea) => Promise.resolve(false), + requestAddProcessedArea: (processesArea) => Promise.resolve(new entities.ProcessedArea()), requestAddArea: (documentId, area) => Promise.resolve(new entities.Area()), requestUpdateArea: (updatedArea) => Promise.resolve(false), requestDeleteAreaById: (areaId) => Promise.resolve(false), @@ -36,6 +36,7 @@ const makeDefaultProject = (): ProjectContextType => ({ requestUpdateProcessedArea: updatedProcessedArea => Promise.resolve(false), requestConnectProcessedAreas: (headId, tailId) => Promise.resolve(false), getSerializedContextGroups: () => Promise.resolve([]), + updateDocuments: () => Promise.resolve(new ipc.GetDocumentsResponse()) }) export default makeDefaultProject diff --git a/frontend/context/Project/provider.tsx b/frontend/context/Project/provider.tsx index 8c8e40c..edb4970 100644 --- a/frontend/context/Project/provider.tsx +++ b/frontend/context/Project/provider.tsx @@ -70,6 +70,7 @@ export function ProjectProvider({ children, projectProps }: Props) { selectedDocumentId, setSelectedDocumentId, currentSession, + updateDocuments, ...areaMethods, ...documentMethods, ...sessionMethods, diff --git a/frontend/context/Project/types.ts b/frontend/context/Project/types.ts index f6b3426..3e37e7c 100644 --- a/frontend/context/Project/types.ts +++ b/frontend/context/Project/types.ts @@ -41,7 +41,7 @@ export type ProjectContextType = { getSelectedDocument: () => entities.Document | undefined getAreaById: (areaId: string) => entities.Area | undefined getProcessedAreasByDocumentId: (documentId: string) => Promise - requestAddProcessedArea: (processedArea: entities.ProcessedArea) => Promise + requestAddProcessedArea: (processedArea: entities.ProcessedArea) => Promise requestAddArea: (documentId: string, area: AddAreaProps) => Promise requestUpdateArea: (area: AreaProps) => Promise requestDeleteAreaById: (areaId: string) => Promise @@ -68,4 +68,5 @@ export type ProjectContextType = { requestUpdateProcessedArea: (updatedProcessedArea: entities.ProcessedArea) => Promise requestConnectProcessedAreas: (headId: string, tailId: string) => Promise getSerializedContextGroups: () => Promise + updateDocuments: () => Promise } & ProjectProps \ No newline at end of file diff --git a/frontend/tailwind.config.js b/frontend/tailwind.config.js index 25fd6ef..b5bdb7c 100644 --- a/frontend/tailwind.config.js +++ b/frontend/tailwind.config.js @@ -16,4 +16,7 @@ module.exports = { }, }, }, + colors: { + brandPrimary: '#dc8dec', + } } \ No newline at end of file diff --git a/frontend/useCases/processImageArea.ts b/frontend/useCases/processImageArea.ts index b4298e9..6e641c5 100644 --- a/frontend/useCases/processImageArea.ts +++ b/frontend/useCases/processImageArea.ts @@ -1,4 +1,4 @@ -import { createScheduler, createWorker } from 'tesseract.js' +import { createScheduler, createWorker, PSM } from 'tesseract.js' import { GetAreaById, GetDocumentById, GetProcessedAreaById, RequestAddProcessedArea, RequestSaveProcessedTextCollection, RequestUpdateProcessedArea } from '../wailsjs/wailsjs/go/ipc/Channel' import { entities } from '../wailsjs/wailsjs/go/models' import loadImage from './loadImage' @@ -79,11 +79,15 @@ const processImageArea = async (documentId: string, areaId: string) => { const existingProcessedArea = await GetProcessedAreaById(areaId) - let didSuccessfullyProcess = false - if (existingProcessedArea.id !== areaId) didSuccessfullyProcess = await RequestAddProcessedArea(newProcessedArea) - else await RequestUpdateProcessedArea(newProcessedArea) - - saveProcessedText() + let didSuccessfullyProcess: boolean // TODO: fix this: this no longer is truthful, returns true or false if there was not a JS error + try { + if (existingProcessedArea.id !== areaId) await RequestAddProcessedArea(newProcessedArea) + else await RequestUpdateProcessedArea(newProcessedArea) + saveProcessedText() + didSuccessfullyProcess = true + } catch (err) { + didSuccessfullyProcess = false + } return didSuccessfullyProcess } diff --git a/frontend/useCases/processImageRect.ts b/frontend/useCases/processImageRect.ts new file mode 100644 index 0000000..470449c --- /dev/null +++ b/frontend/useCases/processImageRect.ts @@ -0,0 +1,103 @@ +import { PSM, createScheduler, createWorker } from 'tesseract.js' +import { GetDocumentById, RequestAddArea, RequestAddProcessedArea } from '../wailsjs/wailsjs/go/ipc/Channel' +import loadImage from './loadImage' +import { entities } from '../wailsjs/wailsjs/go/models' +import { saveProcessedText } from './saveData' + +type rect = { + startX: number, + endX: number, + startY: number, + endY: number, +} + +const processImageRect = async (documentId: string, rectangle: rect): Promise => { + const foundDocument = await GetDocumentById(documentId) + const { path, defaultLanguage } = foundDocument + if (!path || !defaultLanguage) return [] + + const processLanguage = defaultLanguage.processCode + const imageData = await loadImage(path) + + let workerOptions: Partial = {} + if (foundDocument.defaultLanguage.isBundledCustom) { + workerOptions = { + langPath: '/customLanguages', + gzip: false, + // logger: m => console.log(m) + } + } + + const worker = await createWorker(workerOptions) + await worker.loadLanguage(processLanguage) + await worker.initialize(processLanguage) + await worker.setParameters({ + tessedit_pageseg_mode: PSM.AUTO_OSD, + }) + + const scheduler = createScheduler() + scheduler.addWorker(worker) + + const result = await scheduler.addJob('recognize', imageData, { + rectangle: { + left: rectangle.startX, + top: rectangle.startY, + width: rectangle.endX - rectangle.startX, + height: rectangle.endY - rectangle.startY, + } + }) + + const addAreaRequests = result.data.paragraphs.map(async (p: any) => { + const defaultAreaName = p.lines[0]?.words[0]?.text || '' + const area = await RequestAddArea( + documentId, + new entities.Area({ + name: defaultAreaName, + startX: p.bbox.x0, + endX: p.bbox.x1, + startY: p.bbox.y0, + endY: p.bbox.y1, + }) + ) + + const processedArea = await RequestAddProcessedArea(new entities.ProcessedArea({ + id: area.id, + documentId, + order: area.order, + fullText: p.text, + lines: p.lines.map((l: any) => new entities.ProcessedLine({ + fullText: l.text, + words: l.words.map((w: any) => new entities.ProcessedWord({ + areaId: area.id, + fullText: w.text, + direction: w.direction, + confidence: w.confidence, + boundingBox: new entities.ProcessedBoundingBox({ + x0: w.bbox.x0, + y0: w.bbox.y0, + x1: w.bbox.x1, + y1: w.bbox.y1, + }), + symbols: w.symbols.map((s: any) => new entities.ProcessedSymbol({ + fullText: s.text, + confidence: s.confidence, + boundingBox: new entities.ProcessedBoundingBox({ + x0: s.bbox.x0, + y0: s.bbox.y0, + x1: s.bbox.x1, + y1: s.bbox.y1, + }) + })) + })) + })) + })) + return processedArea + }) + + const addAreaResponses = await Promise.allSettled(addAreaRequests) + const areas = addAreaResponses.filter((val): val is PromiseFulfilledResult => val.status === 'fulfilled').map(val => val.value) + await saveProcessedText() + return areas +} + +export default processImageRect diff --git a/frontend/wailsjs/wailsjs/go/ipc/Channel.d.ts b/frontend/wailsjs/wailsjs/go/ipc/Channel.d.ts index 1dca2b1..d9a7302 100755 --- a/frontend/wailsjs/wailsjs/go/ipc/Channel.d.ts +++ b/frontend/wailsjs/wailsjs/go/ipc/Channel.d.ts @@ -35,7 +35,7 @@ export function RequestAddDocument(arg1:string,arg2:string):Promise; -export function RequestAddProcessedArea(arg1:entities.ProcessedArea):Promise; +export function RequestAddProcessedArea(arg1:entities.ProcessedArea):Promise; export function RequestChangeAreaOrder(arg1:string,arg2:number):Promise; @@ -53,6 +53,8 @@ export function RequestDeleteDocumentAndChildren(arg1:string):Promise; export function RequestDeleteProcessedAreaById(arg1:string):Promise; +export function RequestDisconnectProcessedAreas(arg1:string,arg2:string):Promise; + export function RequestSaveContextGroupCollection():Promise; export function RequestSaveDocumentCollection():Promise; diff --git a/frontend/wailsjs/wailsjs/go/ipc/Channel.js b/frontend/wailsjs/wailsjs/go/ipc/Channel.js index ec6a7b2..68a2480 100755 --- a/frontend/wailsjs/wailsjs/go/ipc/Channel.js +++ b/frontend/wailsjs/wailsjs/go/ipc/Channel.js @@ -102,6 +102,10 @@ export function RequestDeleteProcessedAreaById(arg1) { return window['go']['ipc']['Channel']['RequestDeleteProcessedAreaById'](arg1); } +export function RequestDisconnectProcessedAreas(arg1, arg2) { + return window['go']['ipc']['Channel']['RequestDisconnectProcessedAreas'](arg1, arg2); +} + export function RequestSaveContextGroupCollection() { return window['go']['ipc']['Channel']['RequestSaveContextGroupCollection'](); } diff --git a/ipc/ContextGroup.go b/ipc/ContextGroup.go index d38b407..620ddaa 100644 --- a/ipc/ContextGroup.go +++ b/ipc/ContextGroup.go @@ -7,17 +7,39 @@ import ( "textualize/storage" ) +func (c *Channel) RequestDisconnectProcessedAreas(ancestorAreaId string, descendantAreaId string) bool { + contextGroupCollection := contextGroup.GetContextGroupCollection() + + wasSuccessfulDisconnect := contextGroupCollection.DisconnectProcessedAreas(ancestorAreaId, descendantAreaId) + if wasSuccessfulDisconnect { + wasSuccessfulWrite := c.RequestSaveContextGroupCollection() + return wasSuccessfulWrite + } + return false +} + +/* +If a connection already exists, then this method will default to disconnecting the two areas. +*/ func (c *Channel) RequestConnectProcessedAreas(ancestorAreaId string, descendantAreaId string) bool { + contextGroupCollection := contextGroup.GetContextGroupCollection() + + doesContextGroupAlreadyExist := contextGroupCollection.DoesGroupExistBetweenProcessedAreas(ancestorAreaId, descendantAreaId) + if doesContextGroupAlreadyExist { + return c.RequestDisconnectProcessedAreas(ancestorAreaId, descendantAreaId) + } + processedAreaCollection := document.GetProcessedAreaCollection() ancestorArea := processedAreaCollection.GetAreaById(ancestorAreaId) descendantArea := processedAreaCollection.GetAreaById(descendantAreaId) - wasSuccessfulConnect := contextGroup.GetContextGroupCollection().ConnectProcessedAreas(*ancestorArea, *descendantArea) + wasSuccessfulConnect := contextGroupCollection.ConnectProcessedAreas(*ancestorArea, *descendantArea) if wasSuccessfulConnect { wasSuccessfulWrite := c.RequestSaveContextGroupCollection() return wasSuccessfulWrite } + return false } diff --git a/ipc/ProcessedDocument.go b/ipc/ProcessedDocument.go index 93571d3..abc0db8 100644 --- a/ipc/ProcessedDocument.go +++ b/ipc/ProcessedDocument.go @@ -1,7 +1,6 @@ package ipc import ( - "fmt" "sort" document "textualize/core/Document" "textualize/entities" @@ -35,7 +34,7 @@ func (c *Channel) GetProcessedAreasByDocumentId(id string) []entities.ProcessedA return sortedAreas } -func (c *Channel) RequestAddProcessedArea(processedArea entities.ProcessedArea) bool { +func (c *Channel) RequestAddProcessedArea(processedArea entities.ProcessedArea) entities.ProcessedArea { for lineIndex, line := range processedArea.Lines { for wordIndex, word := range line.Words { @@ -46,7 +45,7 @@ func (c *Channel) RequestAddProcessedArea(processedArea entities.ProcessedArea) } document.GetProcessedAreaCollection().AddProcessedArea(processedArea) - return true + return *document.GetProcessedAreaCollection().GetAreaById(processedArea.Id) } func (c *Channel) RequestDeleteProcessedAreaById(id string) bool { @@ -75,9 +74,6 @@ func (c *Channel) RequestDeleteProcessedAreaById(id string) bool { } func (c *Channel) RequestUpdateProcessedArea(updatedProcessedArea entities.ProcessedArea) bool { - fmt.Println("updatedProcessedArea") - fmt.Println(&updatedProcessedArea) - fmt.Println() if updatedProcessedArea.Id == "" { return false } @@ -87,14 +83,13 @@ func (c *Channel) RequestUpdateProcessedArea(updatedProcessedArea entities.Proce return false } - successfulAdd := c.RequestAddProcessedArea(updatedProcessedArea) - if !successfulAdd { - return false - } + addedProcessedArea := c.RequestAddProcessedArea(updatedProcessedArea) + return addedProcessedArea.Id != "" - fmt.Println("document.GetProcessedAreaCollection().GetAreaById(updatedProcessedArea.Id)") - fmt.Println(document.GetProcessedAreaCollection().GetAreaById(updatedProcessedArea.Id)) - return true + // if addedProcessedArea.Id != "" { + // return false + // } + // return true } func (c *Channel) RequestUpdateProcessedWordById(wordId string, newTextValue string) bool {