from qtsymbols import *
import functools, importlib
from traceback import print_exc
import os, gobject, requests, sys, uuid
from myutils.commonbase import maybejson
from myutils.config import globalconfig, _TR, static_data
from myutils.utils import selectdebugfile, makehtml
from myutils.wrapper import Singleton
from gui.usefulwidget import (
    MySwitch,
    getsimpleswitch,
    manybuttonlayout,
    listediterline,
    getsmalllabel,
    TableViewW,
    getsimplepatheditor,
    SuperCombo,
    getsimplecombobox,
    getboxlayout,
    getspinbox,
    SplitLine,
    getIconButton,
    VisLFormLayout,
    LinkLabel,
    DarkLightAutoResetIconHelper,
)
from gui.dynalang import (
    LFormLayout,
    LLabel,
    LPushButton,
    LStandardItemModel,
    LDialog,
    LDialog,
)


class noundictconfigdialog1___(LDialog, DarkLightAutoResetIconHelper):
    def newline(self, row, item: dict):
        items = []
        for _ in self.switchcols:
            items.append(QStandardItem())
        for _ in self.dictkeys:
            items.append(QStandardItem(item.get(_, "")))
        self.model.insertRow(row, items)
        for _, k in enumerate(self.switchkeys):
            self.table.setindexdata(self.model.index(row, _), item.get(k, False))

    def __init__(
        self,
        parent,
        reflist: list,
        title,
        label,
        extraX: dict = None,
        need_regex=True,
        dictkeys=None,
        merged=None,
        mergek=None,
        mergedf=None,
    ) -> None:
        super().__init__(parent, Qt.WindowType.WindowCloseButtonHint)
        self.setWindowTitle(title)
        self.need_regex = need_regex
        self.dictkeys = dictkeys if dictkeys else ["key", "value"]
        self.label = label
        # self.setWindowModality(Qt.ApplicationModal)
        self.reflist = reflist
        formLayout = QVBoxLayout(self)  # 配置layout
        if merged:
            formLayout.addLayout(
                getboxlayout(
                    [
                        getsmalllabel("继承默认"),
                        getsimpleswitch(merged, mergek, default=mergedf),
                        "",
                    ],
                    QHBoxLayout,
                ),
            )
        if extraX:
            ttsprocess = extraX.get("ttsprocess_path")
            if not ttsprocess:
                ttsprocess = str(uuid.uuid4())
                extraX["ttsprocess_path"] = ttsprocess
            last = getIconButton(
                callback=lambda: selectdebugfile(ttsprocess, istts=True),
                icon="fa.edit",
                enable=extraX.get("ttsprocess_use", False),
            )
            switch = getsimpleswitch(
                extraX, "ttsprocess_use", callback=last.setEnabled, default=False
            )
            formLayout.addLayout(
                getboxlayout([getsmalllabel("自定义python处理"), switch, last, 0])
            )
        self.model = LStandardItemModel()
        self.model.setHorizontalHeaderLabels(
            ["正则", "区分大小写", "全字匹配"][(1, 0)[need_regex] :] + label
        )
        table = TableViewW(self, copypaste=True, updown=True)
        table.setModel(self.model)
        for _ in self.textcols:
            table.horizontalHeader().setSectionResizeMode(
                _, QHeaderView.ResizeMode.Stretch
            )
        for _ in self.switchcols:
            table.horizontalHeader().setSectionResizeMode(
                _, QHeaderView.ResizeMode.ResizeToContents
            )

        self.table = table

        search = QHBoxLayout()
        searchcontent = QLineEdit()
        search.addWidget(searchcontent)
        button4 = LPushButton("搜索")

        def clicked4():
            text = searchcontent.text()

            rows = self.model.rowCount()
            cols = self.model.columnCount()
            for row in range(rows):
                ishide = True
                for c in range(cols):
                    if text in self.model.item(row, c).text():
                        ishide = False
                        break
                table.setRowHidden(row, ishide)
            table.updateVisibleArea()

        button4.clicked.connect(clicked4)
        search.addWidget(button4)
        table.getindexdata = self.__getindexwidgetdata
        table.setindexdata = self.__setindexwidget
        table.insertplainrow = lambda row: self.newline(row, {})
        self.table = table
        for row, item in enumerate(reflist):
            self.newline(row, item)
        table.startObserveInserted()
        button = manybuttonlayout(
            [
                ("添加行", functools.partial(table.insertplainrow, 0)),
                ("删除行", self.table.removeselectedrows),
                ("上移", functools.partial(table.moverank, -1)),
                ("下移", functools.partial(table.moverank, 1)),
                ("立即应用", self.apply),
            ]
        )

        formLayout.addWidget(table)
        formLayout.addLayout(search)
        formLayout.addLayout(button)

        self.resize(QSize(600, 400))
        self.show()

    @property
    def textcols(self):
        return tuple(range(2 + self.need_regex, self.model.columnCount()))

    @property
    def textkeys(self):
        return dict(zip(self.dictkeys, self.textcols))

    @property
    def switchcols(self):
        if self.need_regex:
            return (0, 1, 2)
        return (0, 1)

    @property
    def switchkeys(self):
        if self.need_regex:
            return ["regex", "case-sensitive", "whole-word"]
        return ["case-sensitive", "whole-word"]

    def __setindexwidget(self, index: QModelIndex, data):
        if index.column() in self.switchcols:
            bval = self.table.compatiblebool(data)
            self.table.setIndexData(index, bval)
        else:
            self.table.model().setItem(index.row(), index.column(), QStandardItem(data))

    def __getindexwidgetdata(self, index: QModelIndex):
        if index.column() in self.switchcols:
            return index.data(self.table.ValRole)
        return self.model.itemFromIndex(index).text()

    def apply(self):
        def __check(row):
            k = self.table.getdata(row, 2 + self.need_regex)
            if not k:
                return ""
            switchs = tuple(self.table.getdata(row, _) for _ in self.switchcols)
            return (switchs, k)

        self.table.dedumpmodel(__check)
        self.reflist.clear()
        for row in range(self.model.rowCount()):
            d = {}
            for k, v in self.textkeys.items():
                d[k] = self.table.getdata(row, v)
            for i, k in enumerate(self.switchkeys):
                __ = self.table.getdata(row, i)
                if __:
                    d[k] = __
            self.reflist.append(d)

    def closeEvent(self, a0: QCloseEvent) -> None:
        self.setFocus()
        self.apply()


class voiceselect(LDialog):
    voicelistsignal = pyqtSignal(object)

    def __init__(self, *argc, **kwarg):
        super().__init__(*argc, **kwarg)
        self.resize(500, 10)
        self.setWindowTitle("选择声音")
        self.setWindowFlags(
            self.windowFlags() & ~Qt.WindowType.WindowContextHelpButtonHint
        )
        _layout = LFormLayout(self)

        button = QDialogButtonBox(
            QDialogButtonBox.StandardButton.Ok | QDialogButtonBox.StandardButton.Cancel
        )
        button.accepted.connect(self.accept)
        button.rejected.connect(self.reject)

        self.engine_vis = []
        self.engine_internal = []
        for name in globalconfig["reader"]:

            _f = "LunaTranslator/tts/{}.py".format(name)
            if os.path.exists(_f) == False:
                continue
            self.engine_vis.append(globalconfig["reader"][name]["name"])
            self.engine_internal.append(name)
        self.datas = {
            "engine": self.engine_internal[0],
            "voice": None,
            "vis": "",
            "visx": "",
        }
        combo = getsimplecombobox(
            self.engine_vis,
            self.datas,
            "engine",
            internal=self.engine_internal,
            callback=self.__engine_cb,
        )
        _layout.addRow("引擎", combo)
        self._layout = _layout
        combo.currentIndexChanged.emit(combo.currentIndex())
        _layout.addRow(button)
        self.voicelistsignal.connect(self.loadedvoice)
        self.object = None
        self.lastwidget = None

    def loadedvoice(self, obj):
        vl = obj.voiceshowlist
        if self._layout.rowCount() == 3:
            self._layout.removeRow(1)
        self.datas["voice"] = obj.voice
        voices = getsimplecombobox(
            vl,
            self.datas,
            "voice",
            internal=obj.voicelist,
            callback=functools.partial(self._selectvoice, obj),
            sizeX=True,
            static=True,
        )
        self._layout.insertRow(1, "语音", voices)
        voices.currentIndexChanged.emit(voices.currentIndex())

    def _selectvoice(self, obj, internal):
        vis = obj.voiceshowlist[obj.voicelist.index(internal)]
        self.datas["vis"] = self.datas["visx"] + " " + vis

    def __engine_cb(self, internal):
        self.datas["visx"] = self.engine_vis[self.engine_internal.index(internal)]
        self.datas["vis"] = self.datas["visx"]
        self.datas["voice"] = None
        try:
            self.object = gobject.base.loadreader(internal, init=False)
            self.voicelistsignal.emit(self.object)
        except:

            if self._layout.rowCount() == 3:
                self._layout.removeRow(1)


@Singleton
class yuyinzhidingsetting(LDialog):
    def newline(self, row, item):

        self.model.insertRow(
            row,
            [
                QStandardItem(),
                QStandardItem(),
                QStandardItem(),
                QStandardItem(item["key"]),
                QStandardItem(),
            ],
        )
        self.table.setindexdata(self.model.index(row, 0), item.get("range", 0))
        self.table.setindexdata(self.model.index(row, 2), item["regex"])

        self.table.setindexdata(self.model.index(row, 1), item["condition"])
        self.table.setindexdata(self.model.index(row, 4), item["target"])

    def createacombox(self, config):
        com = SuperCombo(sizeX=True)
        com.addItems(["跳过", "默认", "选择声音"])
        target = config.get("target", "skip")
        com.target = target
        if target == "skip":
            com.setCurrentIndex(0)
        elif target == "default":
            com.setCurrentIndex(1)
        else:
            ttsklass, ttsvoice, voicename = target
            com.addItem("[[" + voicename + "]]")
            com.setCurrentIndex(3)
        com.currentIndexChanged.connect(
            functools.partial(self.__comchange, com, config)
        )
        return com

    def __comchange(self, com: SuperCombo, config, idx):
        if idx == 0:
            com.target = "skip"
            if com.count() > 3:
                com.removeItem(com.count() - 1)
        elif idx == 1:
            com.target = "default"
            if com.count() > 3:
                com.removeItem(com.count() - 1)
        elif idx == 2:
            voice = voiceselect(self)
            if voice.exec():
                if voice.datas["voice"] is None:
                    com.setCurrentIndex(1)
                    return
                com.target = (
                    voice.datas["engine"],
                    voice.datas["voice"],
                    voice.datas["vis"],
                )
                com.blockSignals(True)
                com.clear()
                com.addItems(
                    ["跳过", "默认", "选择声音", "[[" + voice.datas["vis"] + "]]"]
                )
                com.setCurrentIndex(3)
                com.blockSignals(False)
            else:
                com.setCurrentIndex(1)

    def __init__(self, parent, reflist, merged=None, mergek=None, mergedf=None) -> None:
        super().__init__(parent, Qt.WindowType.WindowCloseButtonHint)

        self.setWindowTitle("语音指定")

        # self.setWindowModality(Qt.ApplicationModal)
        self.reflist = reflist
        formLayout = QVBoxLayout(self)  # 配置layout
        if merged:
            formLayout.addLayout(
                getboxlayout(
                    [
                        getsmalllabel("继承默认"),
                        getsimpleswitch(merged, mergek, default=mergedf),
                        "",
                    ],
                    QHBoxLayout,
                ),
            )
        self.model = LStandardItemModel()
        self.model.setHorizontalHeaderLabels(["范围", "条件", "正则", "目标", "指定为"])
        table = TableViewW(self, updown=True)
        table.setModel(self.model)
        table.horizontalHeader().setSectionResizeMode(3, QHeaderView.ResizeMode.Stretch)
        table.horizontalHeader().setSectionResizeMode(4, QHeaderView.ResizeMode.Stretch)
        for _ in [0, 1, 2]:
            table.horizontalHeader().setSectionResizeMode(
                _, QHeaderView.ResizeMode.ResizeToContents
            )
        table.getindexdata = self.__getindexwidgetdata
        table.setindexdata = self.__setindexwidget
        table.insertplainrow = lambda row: self.newline(
            row,
            {"key": "", "condition": 0, "regex": False, "target": "skip", "range": 0},
        )
        self.table = table
        for row, item in enumerate(reflist):
            self.newline(row, item)

        search = QHBoxLayout()
        searchcontent = QLineEdit()
        search.addWidget(searchcontent)
        button4 = LPushButton("搜索")

        def clicked4():
            text = searchcontent.text()

            rows = self.model.rowCount()
            cols = self.model.columnCount()
            for row in range(rows):
                ishide = True
                for c in range(cols):
                    if text in self.model.item(row, c).text():
                        ishide = False
                        break
                table.setRowHidden(row, ishide)

        button4.clicked.connect(clicked4)
        search.addWidget(button4)
        button = manybuttonlayout(
            [
                ("添加行", functools.partial(self.table.insertplainrow, 0)),
                ("删除行", table.removeselectedrows),
                ("上移", functools.partial(table.moverank, -1)),
                ("下移", functools.partial(table.moverank, 1)),
                ("立即应用", self.apply),
            ]
        )
        formLayout.addWidget(table)
        formLayout.addLayout(search)
        formLayout.addLayout(button)

        self.resize(QSize(600, 400))
        self.show()

    def __setindexwidget(self, index: QModelIndex, data):
        if index.column() == 0:
            try:
                data = int(data)
            except:
                data = 0
            data = {"range": data}
            self.table.setIndexWidget(
                index, getsimplecombobox(["全部", "原文", "翻译"], data, "range")
            )
        elif index.column() == 2:
            data = {"regex": self.table.compatiblebool(data)}
            self.table.setIndexWidget(index, getsimpleswitch(data, "regex"))
        elif index.column() == 1:
            try:
                data = int(data)
            except:
                data = 0
            data = {"condition": data}
            self.table.setIndexWidget(
                index, getsimplecombobox(["首尾", "包含"], data, "condition")
            )
        elif index.column() == 4:
            if data in ["default", "skip"]:
                pass
            else:
                try:
                    data = self.table.compatiblejson(data)
                except:
                    data = "default"
            self.table.setIndexWidget(index, self.createacombox({"target": data}))
        else:
            self.table.model().setItem(index.row(), index.column(), QStandardItem(data))

    def __getindexwidgetdata(self, index: QModelIndex):
        if index.column() == 0:
            return self.table.indexWidgetX(index).currentIndex()
        if index.column() == 2:
            return self.table.indexWidgetX(index).isChecked()
        if index.column() == 1:
            return self.table.indexWidgetX(index).currentIndex()
        if index.column() == 4:
            return self.table.indexWidgetX(index).target
        return self.model.itemFromIndex(index).text()

    def apply(self):
        self.table.dedumpmodel(3)
        rows = self.model.rowCount()
        self.reflist.clear()
        for row in range(rows):
            k = self.table.getdata(row, 3)
            switch = self.table.getdata(row, 2)
            con = self.table.getdata(row, 1)
            con2 = self.table.getdata(row, 4)
            self.reflist.append(
                {
                    "key": k,
                    "condition": con,
                    "regex": switch,
                    "target": con2,
                    "range": self.table.getdata(row, 0),
                }
            )

    def closeEvent(self, a0: QCloseEvent) -> None:
        self.setFocus()
        self.apply()


def autoinitdialog_items(dic):
    items = []
    for arg in dic["args"]:
        default = dict(name=arg, k=arg, type="lineedit")

        if "argstype" in dic and arg in dic["argstype"]:
            default.update(dic["argstype"][arg])
        items.append(default)
    items.append(dict(type="okcancel", rank=-sys.float_info.min))
    return items


class SuperComboX(SuperCombo):
    def paintEvent(self, e):
        # https://stackoverflow.com/questions/45546155/hide-icon-from-the-label-of-qcombobox
        painter = QStylePainter(self)
        painter.setPen(self.palette().color(QPalette.ColorRole.Text))

        opt = QStyleOptionComboBox()
        self.initStyleOption(opt)

        painter.drawComplexControl(QStyle.ComplexControl.CC_ComboBox, opt)

        opt.currentIcon = QIcon()

        if self.lineEdit():
            le = self.lineEdit()
            edit_rect = self.style().subControlRect(
                QStyle.ComplexControl.CC_ComboBox,
                opt,
                QStyle.SubControl.SC_ComboBoxEditField,
                self,
            )
            le.setGeometry(edit_rect)
        else:
            painter.drawControl(QStyle.ControlElement.CE_ComboBoxLabel, opt)


@Singleton
class autoinitdialog(LDialog, DarkLightAutoResetIconHelper):
    def closeEvent(self, a0):
        if not isqt5:
            for _ in self.__qt6fucker:
                _.setEditable(False)
        return super().closeEvent(a0)

    def __refresh(self, line, combo: SuperCombo):
        try:
            func = getattr(
                importlib.import_module(self.modelfile), line["list_function"]
            )
            items = func(self.maybehasextrainfo, self.regist)
            curr = combo.currentText()
            combo.clear()
            combo.addItems(items)
            if curr in items:
                combo.setCurrentIndex(items.index(curr))

            self.dd[self.refname2line[line["list_cache"]]["k"]] = items
        except Exception as e:
            print_exc()
            if e.args and isinstance(e.args[0], requests.Response):
                resp = e.args[0]
                title = "{} {}: {}".format(resp.status_code, resp.reason, resp.url)
                text = str(maybejson(resp))
                if len(e.args) >= 2:
                    if text:
                        text += "\n"
                    text += e.args[1]
                print(title, text)
                QMessageBox.information(self, title, text)
            else:
                QMessageBox.information(self, str(type(e))[8:-2], str(e))

    def createobject(self, line: "dict", dd: "dict[dict,str|dict]", sub=False):
        if "k" in line:
            key = line["k"]
        if line["type"] == "label":
            lineW = LLabel(dd[key])
        elif line["type"] == "link":
            lineW = LinkLabel()
            lineW.setText(makehtml(dd[key], dd[key]))
        elif line["type"] == "textlist":
            directedit = isinstance(dd[key], str)
            if directedit:
                __list = dd[key].split("|")
            else:
                __list = dd[key].copy()
            lineW = listediterline(
                line["name"],
                __list,
                directedit=directedit,
                issecret=line.get("issecret", False),
            )

            def __getv(l, directedit):
                if directedit:
                    return "|".join(l)
                return l

            self.regist[key] = functools.partial(__getv, __list, directedit)
        elif line["type"] == "custom":
            try:
                lineWF = getattr(
                    importlib.import_module(self.modelfile), line["function"]
                )
                lineW = lineWF(self._dict, key)
                self.updater[key] = lineW.updateValues
            except:
                print_exc()
        elif line["type"] == "combo":
            lineW = SuperCombo()
            items = line["list"]
            lineW.addItems(items, line.get("internal"))

            if "internal" in line:
                lineW.setCurrentData(dd.get(key))
                self.regist[key] = lineW.getCurrentData
            else:
                lineW.setCurrentIndex(dd.get(key, 0))
                self.regist[key] = lineW.currentIndex
            self.cachecombo[key] = lineW
        elif line["type"] == "llm_api_urls":
            lineW = QHBoxLayout()
            combo = SuperComboX()
            combo.setEditable(True)
            self.__qt6fucker.append(combo)
            vis = [
                _["vis"] + "_({})".format(_["value"])
                for _ in static_data["API_URL_PRESETS"]
            ]
            value = [_["value"] for _ in static_data["API_URL_PRESETS"]]
            icons = [
                (
                    QIcon(_["icon"])
                    if isinstance(_["icon"], str)
                    else {
                        "dark": QIcon(_["icon"]["dark"]),
                        "light": QIcon(_["icon"]["light"]),
                    }
                )
                for _ in static_data["API_URL_PRESETS"]
            ]

            def __(combo: SuperCombo, index):
                combo.setCurrentText(combo.getIndexData(index))

            combo.activated.connect(functools.partial(__, combo))
            combo.addItems(vis, value, icons)
            if dd[key] in value:
                combo.setCurrentIndex(value.index(dd[key]))
            combo.setCurrentText(dd[key])
            self.regist[key] = combo.currentText
            lineW.addWidget(combo)
        elif line["type"] == "lineedit_or_combo":
            lineW = QHBoxLayout()
            combo = SuperCombo(static=True)
            combo.setEditable(True)
            self.__qt6fucker.append(combo)
            if "list_function" in line:
                items = dd[self.refname2line[line["list_cache"]]["k"]]
            else:
                items = line["list"]
            combo.addItems(items)
            if dd[key] in items:
                combo.setCurrentIndex(items.index(dd[key]))
            else:
                combo.setCurrentText(dd[key])
            self.regist[key] = combo.currentText
            if "list_function" in line:
                lineW.addWidget(
                    getIconButton(
                        callback=functools.partial(self.__refresh, line, combo),
                        icon="fa.refresh",
                        tips="刷新",
                    )
                )
            lineW.addWidget(combo)
        elif line["type"] == "okcancel":
            lineW = QDialogButtonBox(
                QDialogButtonBox.StandardButton.Ok
                | QDialogButtonBox.StandardButton.Cancel
            )
            lineW.rejected.connect(self.close)
            lineW.accepted.connect(
                functools.partial(self.save, line.get("callback", None))
            )

            lineW.button(QDialogButtonBox.StandardButton.Ok).setText(_TR("确定"))
            lineW.button(QDialogButtonBox.StandardButton.Cancel).setText(_TR("取消"))
        elif line["type"] == "multiline":
            lineW = QPlainTextEdit(dd[key])
            lineW.setPlaceholderText(line.get("placeholder", ""))
            self.regist[key] = lineW.toPlainText
        elif line["type"] == "file":
            __temp = {"k": dd[key]}
            lineW = getsimplepatheditor(
                dd[key],
                line.get("multi", False),
                line.get("dir", False),
                line.get("filter", None),
                callback=functools.partial(__temp.__setitem__, "k"),
                reflist=__temp["k"],
                name=line.get("name", ""),
                dirorfile=line.get("dirorfile", False),
            )

            self.regist[key] = functools.partial(__temp.__getitem__, "k")
        elif line["type"] == "switch":
            lineW = MySwitch(sign=dd[key])
            self.regist[key] = lineW.isChecked
            if not sub:
                _ = QHBoxLayout()
                _.addStretch()
                _.addWidget(lineW)
                _.addStretch()
                lineW = _
        elif line["type"] in ["spin", "intspin"]:

            __temp = {"k": dd[key]}
            lineW = getspinbox(
                line.get("min", 0),
                line.get("max", 100),
                __temp,
                "k",
                line["type"] == "spin",
                line.get("step", (1, 0.1)[line["type"] == "spin"]),
            )
            self.regist[key] = lineW.value
        elif line["type"] == "split":
            lineW = SplitLine()
        else:  # elif line["type"] == "lineedit":
            if not isinstance(dd[key], str):
                return
            lineW = QLineEdit(dd[key])
            lineW.setPlaceholderText(line.get("placeholder", ""))
            self.regist[key] = lineW.text
        return lineW

    def save(self, callback=None):
        for k in self.regist:
            self.dd[k] = self.regist[k]()
        for k in self.updater:
            self.dd.update(self.updater[k]())
        self.close()
        if callback:
            try:
                callback()
            except:
                print_exc()

    def __init__(
        self,
        parent: QWidget,
        dd: "dict",
        title,
        width,
        lines: "list[dict]",
        modelfile=None,
        maybehasextrainfo=None,
        exec_=False,
    ) -> None:
        super().__init__(
            parent,
            Qt.WindowType.WindowCloseButtonHint
            | Qt.WindowType.WindowMaximizeButtonHint,
        )
        self.setWindowIcon(parent.windowIcon())
        self.setWindowTitle(title)
        self.resize(QSize(width, 10))
        formLayout = VisLFormLayout(self)
        self.regist = {}
        self.dd = dd
        self.updater = {}
        self._dict = dd.copy()
        self.modelfile = modelfile
        self.maybehasextrainfo = maybehasextrainfo
        self.__qt6fucker: "list[QComboBox]" = []
        hasrank = []
        negarank = []
        hasnorank = []
        for line in lines:
            rank = line.get("rank", None)
            if rank is None:
                hasnorank.append(line)
                continue
            if rank >= 0:
                hasrank.append(line)
            else:
                negarank.append(line)
        hasrank.sort(key=lambda line: line.get("rank", None))
        negarank.sort(key=lambda line: line.get("rank", None))
        lines = hasrank + hasnorank + negarank

        self.refname2line = {}
        self.appendtoS: "dict[object,dict]" = {}
        for line in lines:
            refswitch = line.get("refswitch", None)
            if refswitch:
                self.refname2line[refswitch] = None
            appends = line.get("appends", None)
            if appends:
                for _ in appends:
                    self.appendtoS[_] = None

            list_cache = line.get("list_cache", None)
            if list_cache:
                self.refname2line[list_cache] = None
        oklines = []

        for line in lines:
            k = line.get("k", None)
            if k in self.refname2line:
                self.refname2line[k] = line
                continue
            if k in self.appendtoS:
                self.appendtoS[k] = line
                continue
            oklines.append(line)
        lines = oklines
        self.cachecombo: "dict[str, SuperCombo]" = {}
        self.cachehasref = {}
        for line in lines:
            if line.get("hide"):
                continue
            try:
                lineW = self.createobject(line, dd)
            except Exception as e:
                print(line)
                raise e
            if not lineW:
                continue
            appends = line.get("appends", None)
            if appends:
                hbox = QHBoxLayout()
                hbox.addWidget(lineW)
                for _ in appends:
                    line_ref = self.appendtoS.get(_, None)
                    if line_ref:
                        object = self.createobject(line_ref, dd, sub=True)
                        hbox.addWidget(getsmalllabel(line_ref.get("name", ""))())
                        hbox.addWidget(object)
                lineW = hbox
            refswitch = line.get("refswitch", None)
            if refswitch:
                hbox = QHBoxLayout()
                line_ref = self.refname2line.get(refswitch, None)
                if line_ref:
                    if "k" in line_ref:
                        key = line_ref["k"]
                    switch = MySwitch(sign=dd[key])
                    self.regist[key] = switch.isChecked
                    switch.clicked.connect(lineW.setEnabled)
                    lineW.setEnabled(dd[key])
                    hbox.addWidget(switch)
                    hbox.addWidget(lineW)
                    lineW = hbox
            if isinstance(lineW, QLayout):
                lineW.setContentsMargins(0, 0, 0, 0)
            if ("name" not in line) or (line["type"] == "split"):
                formLayout.addRow(lineW)
            else:
                formLayout.addRow(line["name"], lineW)

            refcombo = line.get("refcombo")
            if refcombo:
                if refcombo not in self.cachehasref:
                    self.cachehasref[refcombo] = []
                self.cachehasref[refcombo].append((line, formLayout.rowCount() - 1))
        for (
            comboname,
            refitems,
        ) in self.cachehasref.items():

            def refcombofunction(
                refitems: "list[tuple[dict, int]]", combo: SuperCombo, __i
            ):
                viss = []
                for linwinfo, row in refitems:
                    vis = True
                    _i = combo.getIndexData(__i)
                    if _i is None:
                        _i = __i
                    refcombo_i: "str | int | list | tuple" = linwinfo.get("refcombo_i")
                    if isinstance(refcombo_i, (str, int)):
                        vis = refcombo_i == _i
                    elif isinstance(refcombo_i, (list, tuple)):
                        vis = _i in refcombo_i
                    if not vis:
                        formLayout.setRowVisible(row, False)
                    else:
                        viss.append(row)
                for row in viss:
                    formLayout.setRowVisible(row, True)
                QApplication.processEvents()
                self.resize(self.width(), 1)

            self.cachecombo[comboname].currentIndexChanged.connect(
                functools.partial(
                    refcombofunction, refitems, self.cachecombo[comboname]
                )
            )
            self.cachecombo[comboname].currentIndexChanged.emit(
                self.cachecombo[comboname].currentIndex()
            )
        if exec_:
            self.exec()
        else:
            self.show()


class postconfigdialog_1(LDialog):
    def closeEvent(self, a0: QCloseEvent) -> None:
        self.setFocus()
        self.apply()

    def apply(self):
        self.table.dedumpmodel(0)
        rows = self.model.rowCount()
        self.configdict.clear()

        if isinstance(self.configdict, dict):
            for row in range(rows):
                text = self.table.getdata(row, 0)
                self.configdict[text] = self.table.getdata(row, 1)
        elif isinstance(self.configdict, list):
            for row in range(rows):
                text = self.table.getdata(row, 0)
                item = {}
                for _i, key in enumerate(self.dictkeys):
                    item[key] = self.table.getdata(row, _i)
                self.configdict.append(item)
        else:
            raise Exception()

    def __init__(self, parent, configdict, title, headers, dictkeys=None) -> None:
        super().__init__(parent, Qt.WindowType.WindowCloseButtonHint)
        self.setWindowTitle(title)
        formLayout = QVBoxLayout(self)  # 配置layout
        self.dictkeys = dictkeys
        model = LStandardItemModel(len(configdict), 1, self)
        row = 0
        if isinstance(configdict, dict):
            for key1 in configdict:  # 2

                item = QStandardItem(key1)
                model.setItem(row, 0, item)

                item = QStandardItem(configdict[key1])
                model.setItem(row, 1, item)
                row += 1
        elif isinstance(configdict, list):
            for line in configdict:  # 2
                for _i, k in enumerate(dictkeys):
                    item = QStandardItem(line.get(k, ""))
                    model.setItem(row, _i, item)
                row += 1
        else:
            raise Exception()
        model.setHorizontalHeaderLabels(headers)
        table = TableViewW(self, copypaste=True, updown=True)
        table.setModel(model)
        table.setWordWrap(False)
        table.horizontalHeader().setSectionResizeMode(QHeaderView.ResizeMode.Stretch)
        self.table = table
        button = manybuttonlayout(
            (
                ("添加行", table.insertplainrow),
                ("删除行", table.removeselectedrows),
                ("上移", functools.partial(table.moverank, -1)),
                ("下移", functools.partial(table.moverank, 1)),
                ("立即应用", self.apply),
            )
        )
        self.model = model
        self.configdict = configdict
        search = QHBoxLayout()
        searchcontent = QLineEdit()
        search.addWidget(searchcontent)
        button4 = LPushButton("搜索")

        def clicked4():
            text = searchcontent.text()

            rows = model.rowCount()
            cols = model.columnCount()
            for row in range(rows):
                ishide = True
                for c in range(cols):
                    if text in model.item(row, c).text():
                        ishide = False
                        break
                table.setRowHidden(row, ishide)

        button4.clicked.connect(clicked4)
        search.addWidget(button4)

        formLayout.addWidget(table)
        formLayout.addLayout(search)
        formLayout.addLayout(button)
        self.resize(QSize(600, 400))
        self.show()


@Singleton
class postconfigdialog_(postconfigdialog_1):
    pass


def postconfigdialog(parent, configdict, title, header):
    postconfigdialog_(parent, configdict, title, header)


@Singleton
class noundictconfigdialog1(noundictconfigdialog1___):
    pass


def stringreplacedialog(parent, reflistdict, ischild=False):
    args = reflistdict["args"]
    title = reflistdict["name"]
    reflist = args["internal"]
    noundictconfigdialog1(
        parent,
        reflist,
        title,
        ["原文内容", "替换为"],
        merged=args if ischild else None,
        mergek="merge",
        mergedf=False,
    )
