C#ATIA

↑タイトル詐欺 主にFusion360API 偶にCATIA V5 VBA(絶賛ネタ切れ中)

jsTree用代替Jsonを作る

こちらの続きです。
jsTree - C#ATIA
jsTreeの階層を作る為の方法が幾つかあるのですが、
alternative JSON formatと言う方法にしました。
jsTree


正式なjsonフォーマットでは無く、辞書のリストを作り、
辞書内に親のIDを付けておくことで階層表現するものの様です。
本当はAJAXでやりたかったのですが、サンプルすら表示されな
かった為、自分の力量では解決出来なさそうなと判断しました。

作りたいのは指定したフォルダ内のFusion360スクリプト
名前のTreeです。こんな感じです。

# Fusion360API Python script

import traceback
import adsk.fusion
import adsk.core
import pathlib
import json
import re
from typing import List
from dataclasses import dataclass
from dataclasses import field

@dataclass
class ScriptContainer:
    id: int
    path: pathlib.WindowsPath

    def __post_init__(self):
        pass

    def toJson(
        self,
        parent: str = '#'):

        stem = self.path.stem
        # ここでアイコン読み込みたい
        return {
            'id' : self.id,
            'parent' : parent,
            'text' : stem,
            # 'icon' : None,
        }

@dataclass
class ScriptsContainer:
    count: int = field(default=0, compare=False)
    # patterns: List[str] = field(default_factory=list)
    items: List[pathlib.WindowsPath] = field(default_factory=list)

    def add(
        self,
        path: str) -> bool:

        pathObj: pathlib.WindowsPath = pathlib.Path(path)
        if not self.isFusionScript(pathObj):
            return False

        item: dataclass = ScriptContainer(
            self.count,
            pathObj
        )
        self.count += 1
        self.items.append(item)

        return True

    def addInsideFolder(
        self,
        path: str) -> bool:

        pathlib_obj: pathlib.WindowsPath = pathlib.Path(path)
        files = list(pathlib_obj.glob("*"))

        for file in files:
            if file.is_dir() and self.isFusionScript(file):
                self.add(file)

        return True

    def isFusionScript(
        self,
        pathObj: pathlib.Path) -> bool:

        # check filesS
        stem = pathObj.stem
        requiredList = [
            f'{stem}.manifest',
            f'{stem}.py'
        ]

        files = [f.name for f in  list(pathObj.glob("*"))]
        if len(set(requiredList) & set(files)) != len(requiredList):
            return False

        # check manifest
        manifest = pathObj / requiredList[0]
        with open(str(manifest),'r', encoding='utf-8') as f:
            data = f.read()

        data_json = json.loads(data) 

        if not 'type' in data_json:
            return False

        if data_json['type'] != 'script':
            return False

        # # check py
        # manifest = pathObj / requiredList[1]
        # with open(str(manifest),'r', encoding='utf-8') as f:
        #     data = f.read()

        # word = 'def run(context):'
        # if not word in data:
        #     return False

        return True

    def getItemById(
        self,
        id: int) -> dataclass:

        for item in self.items:
            if item.id == id:
                return item

        return None

    def groupBy(
        self) -> list:

        # sort
        items = sorted(self.items, key = lambda x:x.path.stem.lower())

        # key
        # コンストラクタにキーを入れるべき
        patterns = [
            # 'a1',
            ['A-E', '^[a-e]'],
            ['F-J', '^[f-j]'],
            ['K-O', '^[k-o]'],
            ['P-T', '^[p-t]'],
            ['U-Z', '^[u-z]'],
        ]
        otherKey = ['other', 'other']

        group = {key[0]: [] for key in patterns}
        group[otherKey[0]] = []

        for item in items:
            stem = item.path.stem
            hitFg = False
            for pattern in patterns:
                match = re.search(pattern[1], stem.lower())
                if match:
                    group[pattern[0]].append(item)
                    hitFg = True
                    break
            if not hitFg:
                group[otherKey[0]].append(item)

        return group

    def getJstreeJson(
        self):

        # https://www.jstree.com/
        groups = self.groupBy()
        treeContent = []
        groupCount = self.count + 1
        for key in groups:
            if len(groups[key]) < 1:
                continue

            treeContent.append(
                {
                    'id' : groupCount,
                    'parent' : '#',
                    'text' : key,
                }
            )

            for item in groups[key]:
                treeContent.append(item.toJson(groupCount))

            groupCount += 1
        
        return treeContent

def run(context):
    ui = adsk.core.UserInterface.cast(None)
    try:
        app: adsk.core.Application = adsk.core.Application.get()
        ui = app.userInterface

        path = r'C:\temp\Script'

        scripts: dataclass = ScriptsContainer()
        scripts.addInsideFolder(path)
        jstreeJson = scripts.getJstreeJson()

        print(json.dumps(jstreeJson, indent=2))

    except:
        if ui:
            ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))

実行するとこんな感じです。

[
  {
    "id": 59,
    "parent": "#",
    "text": "A-E"
  },
  {
    "id": 0,
    "parent": 59,
    "text": "a1"
  },
  {
    "id": 1,
    "parent": 59,
    "text": "a2"
  },
  {
    "id": 4,
    "parent": 59,
    "text": "a_clone"
  },
・・・

未完成なのですが、これをjsTreeに読み込ませると・・・
f:id:kandennti:20211126175529p:plain
ハメコミ画像ですが、こんな感じです。

何故、こんな中途半端なコードを載せるかと言うと、
一度作りかかっていたものを紛失し、最初から作り直したためです。
(相変わらず管理が悪い)