# -*- coding: utf-8 -*-
"""

/***************************************************************************
 GRMDialog
                                 A QGIS plugin
 GRM
 Generated by Plugin Builder: http://g-sherman.github.io/Qgis-Plugin-Builder/
                             -------------------
        begin                : 2019-12-18
        git sha              : $Format:%H$
        copyright            : (C) 2019 by KICT/Hermesys
        email                : shpark@hermesys.co.kr
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 ***************************************************************************/
"""

import os
import xml.etree.ElementTree as ET
from typing import List

from qgis.core import (
    QgsGeometry,
    QgsPointXY,
    QgsProject,
    QgsRaster,
    QgsRasterLayer,
    QgsRectangle,
    QgsVectorLayer,
)
from qgis.gui import (
    QgsMapTool,
    QgsMapToolPan,
    QgsMapToolZoom,
    QgsRubberBand,
    QgsVertexMarker,
)
from qgis.PyQt import QtGui, QtWidgets
from qgis.PyQt.QtCore import QDateTime, QFileInfo, QSize, Qt, pyqtSignal
from qgis.PyQt.QtGui import QColor
from qgis.PyQt.QtWidgets import (
    QAbstractItemView,
    QAction,
    QColorDialog,
    QDockWidget,
    QGridLayout,
    QInputDialog,
    QLineEdit,
    QListWidgetItem,
    QMessageBox,
    QPushButton,
    QRadioButton,
    QTabBar,
    QTableWidgetItem,
    QWidget,
)

from grm.AddFlowControl_dialog import AddFlowControl
from grm.css import css_sheet
from grm.lib.Get_Set import set_Controls
from grm.lib.GRM_DLL import grmWSinfo
from grm.lib.Raster import AscToShape
from grm.lib.Util import Execute, MsError, MsInfo, Opewn_ViewFile
from grm.lib.xmltodict import parse, unparse
from grm.plugin.flow_layer import get_flow_layer
from grm.plugin.grid_layer import get_point_layer
from grm.ui.GRM_dialog_base import Ui_MainWindow
from grm.utils.enum_types import (
    EnumInterceptionMethod,
    EnumPETMethod,
    EnumSnowMeltMethod,
)
from grm.XMLCheck import xmls
from grm.utils.ex_float_conv import ex_to_float

_get_set_control = set_Controls()
_XmlCheck = xmls()


class GRMDialog(QtWidgets.QMainWindow, Ui_MainWindow):
    closeDialogEvent = pyqtSignal()

    def __init__(
        self,
        _xmltodict={},
        _WatchPointCount=0,
        _SubWatershedCount=0,
        _GreenAmptCount=0,
        _SoilDepthCount=0,
        _LandCoverCount=0,
        _FlowControlCount=0,
        _ChannelSettingsCount=0,
        parent=None,
    ):
        super(GRMDialog, self).__init__(parent)
        self.setupUi(self)
        self._StreamWSID = []
        self._wsinfo = None
        self._Flowcontrolgrid_flag = False

        self._xmltodict = _xmltodict
        self._WatchPointCount = _WatchPointCount
        self._SubWatershedCount = _SubWatershedCount
        self._GreenAmptCount = _GreenAmptCount
        self._SoilDepthCount = _SoilDepthCount
        self._LandCoverCount = _LandCoverCount
        self._FlowControlCount = _FlowControlCount
        self._ChannelSettingsCount = _ChannelSettingsCount
        self._Flowcontrolgrid_flag = True

        self.canvasRubberBand = []

        self.qTabBar()
        self.firstTab.currentChanged.connect(lambda: self.connectionTabBar("first"))
        self.secondTab.currentChanged.connect(lambda: self.connectionTabBar("second"))

        # 2020-01-20 박: 프로젝트 데이터 초기 셋팅
        self.Set_ProjectDataInit()

        # 2020-01-09 박: 스타일 적용
        self.setStyleSheet(css_sheet)
        self.groupBox_2.setStyleSheet("QGroupBox{padding-top:15px;margin-top:-15px;}")
        self.groupBox_6.setStyleSheet("QGroupBox{padding-top:15px;margin-top:-15px;}")

        # 2020-01-09 박:캔버스 툴 버튼 아이콘 셋팅
        self.Set_Canvas_Tool_Icon()

        # 2020-01-20 박:캔버스에 레이어 올리기
        self.Set_Canvas_Layer_default()

        # 시뮬레이션 탭 기능 기본값 셋팅
        self.Set_simulation_tab_default()
        # default 설정이지만 프로그램 흐름상 나중에 처리 해야 하는 목록
        # Watchpoint 체크박스 선택 상태로 처리
        self.chkWatch_Point.setChecked(True)
        self.chkFlowContorGird.setChecked(True)

        self.watchpoint()

        self.click_FlowContorGird()

        # WatchPoint 탭 기능 기본값 셋팅
        # 프로젝트 파일을 읽고 테이블에 셋팅(watch point)
        self.Set_Wathpoint_tab_default()

        # Channel CS 탭 기능 기본값 셋팅
        self.Set_ChannelCS_tab_default()

        # Watershed 탭 기능 기본값 셋팅
        # 데이터 값들이 다 들어 오지 않았음 확인 해야 함
        self.Set_Watershed_Parameter_tab_default()

        # Flow Control 탭 기능 기본값 셋팅
        self.Set_FlowControl_tab_default()

        # 2020-01-20 박: dockwidget 창 분리 비활성화
        self.dockDisableButton()

        _get_set_control.GlobalLabel(self.lblColRow)

        # Cell info Flow 텍스트 박스에 값 셋팅에 사용 하기 위해 유틸에 텍스트 박스 넘김
        _get_set_control.GlobalControl(
            self.txtCellCount,
            self.txtCelltype,
            self.txtStreamValue,
            self.txtFD,
            self.txtFA,
            self.txtSlope,
            self.txtWatershedID,
        )

        # Cell info Land cover
        _get_set_control.GlobalControl_Landcover(
            self.txtLandGridValue,
            self.txtLandType,
            self.txtRoughness,
            self.txtratio,
            self.txtCanopyRatio,
            self.txtInterceptionMaxWaterCanopy,
        )

        # Cell info Depth
        _get_set_control.GlobalControl_Depth(
            self.txtDepthValue, self.txtSoilDepthClass, self.txtSoilDepth
        )

        # Cell info Texture
        _get_set_control.GlobalControl_texture(
            self.txtTextureGridValue,
            self.txtSoilTexture,
            self.txtPorosity,
            self.txtEffectivePorosity,
            self.txtSuctionhead,
            self.txtcondcutivity,
        )

        _get_set_control.set_GreenAmptCount(self._GreenAmptCount)
        _get_set_control.set_SoilDepthCount(self._SoilDepthCount)
        _get_set_control.set_LandCoverCount(self._LandCoverCount)
        _get_set_control.set_xmltodict(self._xmltodict)

        self.dataTimeFormat = self.chkStartingTime.isChecked()

        # 2020-01-20 박: 캔버스 툴 셋팅
        self.Set_Cavas_tool_btn()

        self.btnStart_Simulation.clicked.connect(self.Click_StartSimulation)
        self.btnSaveproject.clicked.connect(lambda: self.SaveProject(True))
        self.btnViewResult.clicked.connect(self.Open_ViewResult)
        self.btnClose.clicked.connect(self.Close_Form)

    def Click_StartSimulation(self):
        # 값 변경 테스트 용 WatershedFile 파일 경로를 바꿈
        GRMCore_exe = os.path.dirname(os.path.realpath(__file__)) + "\DLL\GRM.exe"
        self.SaveProject(False)

        option = "/a " if self.chkAutoROM.isChecked() else ""
        arg = f'"{GRMCore_exe}" {option}"{self.ProjectFile}"'

        result = Execute(arg)

        msg = "Simulation completed"
        if result != 1:
            msg = "Simulation was stopped."

        MsInfo(msg)

    def qTabBar(self):
        self.firstTab = QTabBar()
        self.secondTab = QTabBar()
        layout = QGridLayout()
        baseLayout = self.centralwidget.layout()

        self.firstTab.addTab("")
        self.firstTab.addTab("Simulation")
        self.firstTab.addTab("Watch points")
        self.firstTab.addTab("Channel cross section")

        self.secondTab.addTab("")
        self.secondTab.addTab("Flow control")
        self.secondTab.addTab("Watershed parameters")
        self.secondTab.addTab("Cell Info.")

        self.firstTab.setExpanding(False)  # 창 넓이에 맞춰 늘어나지 않음
        self.secondTab.setExpanding(False)
        style = "QTabBar::tab:first{ max-width: 0px; } QTabBar::tab:first:selected{ border: 0px; }"
        self.firstTab.setStyleSheet(style)
        self.secondTab.setStyleSheet(style)
        self.firstTab.setDrawBase(False)  # 탭 하단에 선을 표시하지 않음

        # layout 세팅
        # r, c, rspan, cspan
        layout.addWidget(self.firstTab, 0, 0, 1, 2)
        layout.addWidget(self.secondTab, 1, 0, 1, 2)
        layout.addWidget(self.stackedWidget, 2, 0, 1, 2)
        layout.setSpacing(0)
        self.gridLayout_10.setSpacing(0)
        self.centralwidget.setLayout(layout)
        baseLayout.addLayout(layout, 0, 0, 2, 2)
        baseLayout.addWidget(self.btnStart_Simulation, 2, 0)
        baseLayout.addWidget(self.btnSaveproject, 2, 1)
        baseLayout.addWidget(self.btnViewResult, 3, 0)
        baseLayout.addWidget(self.btnClose, 3, 1)
        baseLayout.addWidget(self.mapcanvas, 1, 2, 3, 2)

        self.firstTab.setCurrentIndex(1)

    def Set_ProjectDataInit(self):
        # 그리드 라인 에 사용될 변수
        # 글로벌 변수로 지정 해서 사용 하면 화면을 닫았다가 다시 켜면 값이 남아 있어서 그리드 라인이 안그려짐
        self.grid_line = {}

        # direction 그리때 사용 변수
        # 글로벌 변수로 지정 해서 사용 하면 화면을 닫았다가 다시 켜면 값이 남아 있어서 디렉션이 안그려짐
        self.flow_direction = {}

        project_settings = self._xmltodict["GRMProject"]["ProjectSettings"]

        # 프로젝트 파일 경로 변수 셋팅
        self.ProjectFile = project_settings["ProjectFile"]

        # watershed Layer file 경로 변수
        self.LayerPath = project_settings["DomainFile"]

        # simulation Tab 변수
        self.ComputationalTimeStep_min = project_settings["ComputationalTimeStep_min"]
        self.MaxDegreeOfParallelism = project_settings["MaxDegreeOfParallelism"]
        self.SimulationDuration_hr = project_settings["SimulationDuration_hr"]
        self.OutputTimeStep_min = project_settings["OutputTimeStep_min"]
        self.SimulateInfiltration = project_settings["SimulateInfiltration"]
        self.SimulateSubsurfaceFlow = project_settings["SimulateSubsurfaceFlow"]
        self.SimulateBaseFlow = project_settings["SimulateBaseFlow"]
        self.SimulateInterception = project_settings["SimulateInterception"]
        self.SimulateEvapotranspiration = project_settings["SimulateEvapotranspiration"]
        self.SimulateSnowMelt = project_settings["SimulateSnowMelt"]
        self.SimulateFlowControl = project_settings["SimulateFlowControl"]
        self.IsFixedTimeStep = project_settings["IsFixedTimeStep"]
        self.SimulationStartingTime = project_settings["SimulationStartingTime"]
        self.WatershedFile = project_settings["DomainFile"]
        self.SlopeFile = project_settings["SlopeFile"]
        self.FlowDirectionFile = project_settings["FlowDirectionFile"]
        self.FlowAccumFile = project_settings["FlowAccumFile"]
        self.StreamFile = project_settings["StreamFile"]
        self.ChannelWidthFile = project_settings["ChannelWidthFile"]
        self.LandCoverFile = project_settings["LandCoverFile"]
        self.SoilTextureFile = project_settings["SoilTextureFile"]
        self.SoilDepthFile = project_settings["SoilDepthFile"]
        self.InitialChannelFlowFile = project_settings["InitialChannelFlowFile"]
        self.InitialSoilSaturationRatioFile = project_settings[
            "InitialSoilSaturationRatioFile"
        ]
        self.MakeIMGFile = project_settings["MakeIMGFile"]
        self.MakeASCFile = project_settings["MakeASCFile"]
        self.MakeSoilSaturationDistFile = project_settings["MakeSoilSaturationDistFile"]
        self.MakeRfDistFile = project_settings["MakeRfDistFile"]
        self.MakeRFaccDistFile = project_settings["MakeRFaccDistFile"]
        self.MakeFlowDistFile = project_settings["MakeFlowDistFile"]
        self.PrintOption = project_settings["PrintOption"]
        self.PrintAveValue = project_settings["PrintAveValue"]
        self.AveValueTimeInterval_min = project_settings["AveValueTimeInterval_min"]
        self.WriteLog = project_settings["WriteLog"]

        if self.InitialChannelFlowFile is None:
            self.InitialChannelFlowFile = ""
        if self.InitialSoilSaturationRatioFile is None:
            self.InitialSoilSaturationRatioFile = ""
        if self.ChannelWidthFile is None:
            self.ChannelWidthFile = ""

        # Core DLL 연동 작업 선행 처리
        FDType = project_settings["FlowDirectionType"]

        # 2020-05-12 박: 추가 된 기능  (dll에 정보 넘겨주고 값 받기)
        self._wsinfo = grmWSinfo(
            FDType,
            self.WatershedFile,
            self.SlopeFile,
            self.FlowDirectionFile,
            self.FlowAccumFile,
            self.StreamFile,
            self.LandCoverFile,
            self.SoilTextureFile,
            self.SoilDepthFile,
            self.InitialSoilSaturationRatioFile,
            self.InitialChannelFlowFile,
            self.ChannelWidthFile,
        )
        _get_set_control.set_wsinfo(self._wsinfo)
        self.GridCellSize = self._wsinfo.cellSize

        # 임시 리스트를 만들어서 데이터를 받고 받은 데이터를 _StreamWSID 에 셋팅
        try:
            self._StreamWSID = []
            WSIDs = []
            WSIDs = self._wsinfo.mostDownStreamWSIDs
            for i in range(self._wsinfo.mostDownStreamWSCount):
                if WSIDs[i] is not None:
                    self._StreamWSID.append(str(WSIDs[i]))
        except Exception as e:
            MsInfo(e)

        # 2020-05-13 박: 지금 함수가 확인이 안되서 임시로 주석 처리
        self.Set_Wathpoint_default_value()

        # ChannelWidth tab 변수
        self.WSID = []
        self.CrossSectionType = []
        self.SingleCSChannelWidthType = []
        self.ChannelWidthEQc = []
        self.ChannelWidthEQd = []
        self.ChannelWidthEQe = []
        self.ChannelWidthMostDownStream = []
        self.LowerRegionHeight = []
        self.LowerRegionBaseWidth = []
        self.UpperRegionBaseWidth = []
        self.CompoundCSChannelWidthLimit = []
        self.BankSideSlopeRight = []
        self.BankSideSlopeLeft = []

        channelDic = {
            "CrossSectionType": ["CSSingle", self.CrossSectionType],
            "SingleCSChannelWidthType": ["CWGeneration", self.SingleCSChannelWidthType],
            "ChannelWidthEQc": ["1.698", self.ChannelWidthEQc],
            "ChannelWidthEQd": ["0.318", self.ChannelWidthEQd],
            "ChannelWidthEQe": ["0.5", self.ChannelWidthEQe],
            "ChannelWidthMostDownStream": [
                str(self.GridCellSize),
                self.ChannelWidthMostDownStream,
            ],
            "LowerRegionHeight": ["0", self.LowerRegionHeight],
            "LowerRegionBaseWidth": ["0", self.LowerRegionBaseWidth],
            "UpperRegionBaseWidth": ["0", self.UpperRegionBaseWidth],
            "CompoundCSChannelWidthLimit": ["0", self.CompoundCSChannelWidthLimit],
            "BankSideSlopeRight": ["1.5", self.BankSideSlopeRight],
            "BankSideSlopeLeft": ["1.5", self.BankSideSlopeLeft],
        }

        if self._ChannelSettingsCount == 0:
            self.lisw_WSID.clear()
            # 2020-05-25 박: New 프로젝트 시행시에 값을 받아 오는 부분이 없어서 추가
            self._ChannelSettingsCount = len(self._StreamWSID)
            if self._ChannelSettingsCount > 0:
                DictoXml = unparse(self._xmltodict)
                ET.register_namespace("", "http://tempuri.org/GRMProject.xsd")
                xmltree = ET.ElementTree(ET.fromstring(DictoXml))
                root = xmltree.getroot()
                for i in range(len(self._StreamWSID)):
                    child = ET.Element("ChannelSettings")
                    root.append(child)

                    ChannelWSID = ET.Element("WSID")
                    ChannelWSID.text = str(self._StreamWSID[i])
                    child.append(ChannelWSID)

                    self.WSID.append(str(self._StreamWSID[i]))
                    item1 = QListWidgetItem(str(self._StreamWSID[i]))
                    self.lisw_WSID.addItem(item1)

                    for k in channelDic.keys():
                        ele = ET.Element(k)
                        ele.text = channelDic[k][0]
                        child.append(ele)
                        channelDic[k][1].append(channelDic[k][0])

                xmltree_string = ET.tostring(xmltree.getroot())
                docs = dict(parse(xmltree_string))
                self._xmltodict.clear()
                self._xmltodict.update(docs)

        elif self._ChannelSettingsCount == 1:
            self.lisw_WSID.clear()
            result = self._xmltodict["GRMProject"]["ChannelSettings"]["WSID"]
            self.WSID.append(self._xmltodict["GRMProject"]["ChannelSettings"]["WSID"])
            item1 = QListWidgetItem(str(self.WSID[0]))
            self.lisw_WSID.addItem(item1)

            for k in channelDic:
                value = self._xmltodict["GRMProject"]["ChannelSettings"][k]
                if k == "ChannelWidthMostDownStream" and not str(value).strip():
                    value = str(int(self.GridCellSize))
                channelDic[k][1].append(value)

            self._ChannelSettingsCount = 1

        elif self._ChannelSettingsCount > 1:
            self.lisw_WSID.clear()
            i = 0
            for flowitem in self._xmltodict["GRMProject"]["ChannelSettings"]:
                self.WSID.append(str(flowitem["WSID"]))
                item1 = QListWidgetItem(str(self.WSID[i]))
                self.lisw_WSID.addItem(item1)
                self.CrossSectionType.append(str(flowitem["CrossSectionType"]))
                self.SingleCSChannelWidthType.append(
                    str(flowitem["SingleCSChannelWidthType"])
                )
                self.ChannelWidthEQc.append(str(flowitem["ChannelWidthEQc"]))
                self.ChannelWidthEQd.append(str(flowitem["ChannelWidthEQd"]))
                self.ChannelWidthEQe.append(str(flowitem["ChannelWidthEQe"]))

                DSValue = str(flowitem["ChannelWidthMostDownStream"])
                if str(DSValue).strip():
                    self.ChannelWidthMostDownStream.append(DSValue)
                else:
                    self.ChannelWidthMostDownStream.append(str(int(self.GridCellSize)))

                self.LowerRegionHeight.append(str(flowitem["LowerRegionHeight"]))
                self.LowerRegionBaseWidth.append(str(flowitem["LowerRegionBaseWidth"]))
                self.UpperRegionBaseWidth.append(str(flowitem["UpperRegionBaseWidth"]))
                self.CompoundCSChannelWidthLimit.append(
                    str(flowitem["CompoundCSChannelWidthLimit"])
                )
                self.BankSideSlopeRight.append(str(flowitem["BankSideSlopeRight"]))
                self.BankSideSlopeLeft.append(str(flowitem["BankSideSlopeLeft"]))
                i = i + 1
            self._ChannelSettingsCount = i

        self.flowEle = [
            "Name",
            "ColX",
            "RowY",
            "DT_min",
            "ControlType",
            "FlowDataFile",
            "IniStorage",
            "MaxStorage",
            "NormalHighStorage",
            "RestrictedStorage",
            "RestrictedPeriod_Start",
            "RestrictedPeriod_End",
            "ROType",
            "AutoROMmaxOutflow_CMS",
            "ROConstQ",
            "ROConstQDuration",
        ]

    def SetMostDownStream(self, id):
        try:
            # 만약에 Cell size 값이 없으면 레이어에서 값을 받음
            if self.GridCellSize is None:
                self.GridCellSize = str(self._xsize) if self._xsize else "0"
            Allsize = self.GridCellSize

            IniSaturation = "0.9"
            MinSlopeOF = "0.0001"
            MinSlopeChBed = "0.0001"
            intAll = float(Allsize)
            #             if intAll > 0:
            #                 MinChBaseWidth = intAll / 10
            MinChBaseWidth = intAll / 10 if intAll > 0 else 0
            IniFlow = "0"
            ChRoughness = "0.045"
            DryStreamOrder = "0"
            CalCoefLCRoughness = "1"
            CalCoefSoilDepth = "1"
            CalCoefPorosity = "1"
            CalCoefWFSuctionHead = "1"
            CalCoefHydraulicK = "1"
            UnsturatedType = 1
            CoefUnsatruatedk = "0.2"
            interceptMethod = 1
            potentialETMethod = 2
            etCoeff = "1"
            snowMeltMethod = 1
            tempSnowRain = "0"
            smeltingTemp = "1"
            snowCovRatio = "1"
            smeltCoef = "1"
            self._wsinfo.setOneSWSParsAndUpdateAllSWSUsingNetwork(
                int(id),  # int wsid,
                float(IniSaturation),  # double iniSat,
                float(MinSlopeOF),  # double minSlopeLandSurface,
                int(UnsturatedType),  # int unSKType,
                float(CoefUnsatruatedk),  # double coefUnsK,
                float(MinSlopeChBed),  # double minSlopeChannel,
                float(MinChBaseWidth),  # double minChannelBaseWidth,
                float(ChRoughness),  # double roughnessChannel,
                int(DryStreamOrder),  # int dryStreamOrder,
                float(CalCoefLCRoughness),  # double ccLCRoughness,  
                float(CalCoefPorosity),  # double ccPorosity,
                float(CalCoefWFSuctionHead),  # double ccWFSuctionHead,
                float(CalCoefHydraulicK),  # double ccSoilHydraulicCond,
                float(CalCoefSoilDepth),  # double ccSoilDepth,
                int(interceptMethod),
                int(potentialETMethod),
                float(etCoeff),
                int(snowMeltMethod),
                float(tempSnowRain),
                float(smeltingTemp),
                float(snowCovRatio),
                float(smeltCoef),
                0,
            )  # double iniFlow = 0)
        except Exception as e:
            MsError(e)

    def dockDisableButton(self):
        dockList = self.stackedWidget.findChildren(QDockWidget)
        for dock in dockList:
            dock.setFeatures(QDockWidget.NoDockWidgetFeatures)

    def connectionTabBar(self, type):
        f = self.firstTab.currentIndex()
        s = self.secondTab.currentIndex()
        index = 0

        if type == "second" and s > 0:
            self.firstTab.setCurrentIndex(0)
            self.secondTab.setCurrentIndex(s)
            index = s + (self.firstTab.count() - 2)
        elif type == "first" and f > 0:
            self.secondTab.setCurrentIndex(0)
            self.firstTab.setCurrentIndex(f)
            index = f - 1

        self.stackedWidget.setCurrentIndex(index)

    # canvas 버튼 아이콘 이미지 설정
    def Set_Canvas_Tool_Icon(self):
        root = os.path.dirname(os.path.abspath(__file__)) + "\image"
        ZoomExtent = root + "\ZoomExtent.png"
        Zoomin = root + "\ZoomIn.png"
        ZoomOut = root + "\ZoomOut.png"
        Pan = root + "\Pan.png"
        Zoomnext = root + "\Zoomnext.png"
        ZoomPrevious = root + "\ZoomPrevious.png"
        SelectGrid = root + "\SelectGrid.png"
        MoveTo = root + "\MoveTo.png"

        self.btnZoomExtent.setIcon(QtGui.QIcon(ZoomExtent))
        self.btnZoomExtent.setIconSize(QSize(200, 200))

        self.btnZoomIn.setIcon(QtGui.QIcon(Zoomin))
        self.btnZoomOut.setIcon(QtGui.QIcon(ZoomOut))
        self.btnPan.setIcon(QtGui.QIcon(Pan))
        self.btnZoomnext.setIcon(QtGui.QIcon(Zoomnext))
        self.btnZoomprevious.setIcon(QtGui.QIcon(ZoomPrevious))
        self.btnSelectgrid.setIcon(QtGui.QIcon(SelectGrid))
        self.btnMoveto.setIcon(QtGui.QIcon(MoveTo))

    # 캔버스 툴 기능 연동
    def Set_Cavas_tool_btn(self):
        self.tool = CanvasTool(self.mapcanvas)

        # ZoomExtent
        self.btnZoomExtent.clicked.connect(self.tool.ZoomtoExtent)

        # Zoom Next
        self.btnZoomnext.clicked.connect(self.tool.ZoomtoNextExtent)

        # Zoom Previous
        self.btnZoomprevious.clicked.connect(self.tool.ZoomtoPrevious)

        # Zoom In
        self.btnZoomIn.clicked.connect(self.tool.canvas_zoomIn)

        # Zoom Out
        self.btnZoomOut.clicked.connect(self.tool.canvas_zoomOut)

        # Pan
        self.btnPan.clicked.connect(self.tool.canvas_pan)

        # Moveto
        self.btnMoveto.clicked.connect(self.aboutApp)

        # # Selectgrid
        self.btnSelectgrid.clicked.connect(self.identify)

        # Watch_Point 기본 설정은 체크
        self.chkWatch_Point.stateChanged.connect(self.watchpoint)

        # chkFC
        self.chkFlowContorGird.stateChanged.connect(self.click_FlowContorGird)

        # 체크 박스 눌렀을때 캔버스에 그리드 라인 추가 함수
        self.show_grid_line.clicked.connect(self.show_hide_grid_line)

        # 캔버스에 Flow direction
        self.show_flow_direction.clicked.connect(self.show_hide_flow_direction)

    # 캔버스에 레이어 올리기
    def Set_Canvas_Layer_default(self):
        # canvase 레이어 올리기
        if self.LayerPath is not None:
            convert_shape_path = self.LayerPath.upper().replace(
                ".ASC", "_temp_convert_file.SHP"
            )
            flag_WSID_Shape = AscToShape(self.LayerPath, convert_shape_path)
            Wsid_shape_style_path_ori = (
                os.path.dirname(os.path.realpath(__file__)) + "\DLL\Label_Style.qml"
            )

            #             self.layer = QgsRasterLayer(self.LayerPath, "FA", "gdal")
            self.layer = QgsRasterLayer(self.LayerPath, "WSFAlayerload", "gdal")
            self.Wsid_label_shape = QgsVectorLayer(convert_shape_path, "WSID_label")
            self.Wsid_label_shape.loadNamedStyle(Wsid_shape_style_path_ori)
            # 캔버스의 기본 정보를 Global에 대입 다른 클래스에서 사용
            _layer = self.layer
            self.Set_Global_CanvaseValue()

            """#2017.11..1 원 :
                문제1. 상기 ASC가 투영 좌표계 레이어인데. 경위도로 오인 지정되어 있었슴. 이는 PRJ 파일 만듧면 해결됨.
                문제2 .그리고 canvas 는 직접 setDestinationCrs 해야 좌표계가 지정됨. https://issues.qgis.org/issues/9772 """

            self.mapcanvas.setDestinationCrs(self.layer.crs())
            QgsProject.instance().addMapLayer(self.layer, False)
            self.mapcanvas.setExtent(self.layer.extent())
            self.mapcanvas.setLayers([self.layer, self.Wsid_label_shape])

    # 레이어 기본 값을 Global 로 지정해서 정의
    def Set_Global_CanvaseValue(self):
        self._width = self.layer.width()
        self._height = self.layer.height()
        self._xsize = self.layer.rasterUnitsPerPixelX()
        self._ysize = self.layer.rasterUnitsPerPixelY()
        self._extent = self.layer.extent()
        self._ymax = self._extent.yMaximum()
        self._ymin = self._extent.yMinimum()
        self._xmax = self._extent.xMaximum()
        self._xmin = self._extent.xMinimum()

    # def 연동 함수
    def Open_ViewResult(self):
        self.disCharge = self._xmltodict["GRMProject"]["ProjectSettings"]["ProjectFile"]
        disCharge_path = os.path.splitext(os.path.basename(self.disCharge))[0]
        self.disCharge = self.disCharge.replace(
            disCharge_path + ".gmp", disCharge_path + "_Discharge.out"
        )
        Opewn_ViewFile(self.disCharge)

    # ----------------- 2017-10-24_오전 박 simulation 탭 텍스트 박스 셋팅 -----------------------------
    def Set_simulation_tab_default(self):
        # 프린트 옵션 콤보 박스 셋팅
        combolist = (
            "All",
            "DischargeFile",
            "DischargeAndFcFile",
            "AverageFile",
            "DischargeFileQ",
            "AverageFileQ",
            "AllQ",
        )
        self.cmbPrint.addItems(combolist)
        index = self.cmbPrint.findText(self.PrintOption, Qt.MatchFixedString)
        if index >= 0:
            self.cmbPrint.setCurrentIndex(index)

        self.cmbPrint.currentIndexChanged.connect(self.printcombo)
        self.spTimeStep_min_2.valueChanged.connect(self.SPvaluechange)

        self.chkParallel.stateChanged.connect(self.Check_Parallel)
        self.Check_Parallel()

        self.chkPrintAveValue.stateChanged.connect(self.Check_Ave_Value_Time)
        self.Check_Ave_Value_Time()

        self.chkInterception.stateChanged.connect(
            lambda state: self.check_simulate_option(
                state,
                [self.groupSimulateInterception, self.txtInterceptionMaxWaterCanopy],
            )
        )
        self.check_simulate_option(
            self.chkInterception.isChecked(),
            [self.groupSimulateInterception, self.txtInterceptionMaxWaterCanopy],
        )

        self.chkEvapotranspiration.stateChanged.connect(
            lambda state: self.check_simulate_option(
                state, [self.groupSimulateEvapotranspiration]
            )
        )
        self.check_simulate_option(
            self.chkEvapotranspiration.isChecked(),
            [self.groupSimulateEvapotranspiration],
        )

        self.chkSnowMelt.stateChanged.connect(
            lambda state: self.check_simulate_option(
                state, [self.groupSimulateSnowMelt, self.txtCanopyRatio]
            )
        )
        self.check_simulate_option(
            self.chkSnowMelt.isChecked(),
            [self.groupSimulateSnowMelt, self.txtCanopyRatio],
        )

        self.chkFlowControl.toggled.connect(self.Check_Flow)
        self.Check_Flow(False)

        self.chkmakeimage.setChecked(False)
        if self.MakeIMGFile.upper() == "TRUE":
            self.chkmakeimage.setChecked(True)

        self.chkmakeASC.setChecked(False)
        if self.MakeASCFile.upper() == "TRUE":
            self.chkmakeASC.setChecked(True)

        self.chksoiSaturation.setChecked(False)
        if self.MakeSoilSaturationDistFile.upper() == "TRUE":
            self.chksoiSaturation.setChecked(True)

        self.chkrfDistFile.setChecked(False)
        if self.MakeRfDistFile.upper() == "TRUE":
            self.chkrfDistFile.setChecked(True)

        self.chkrfaacDistfile.setChecked(False)
        if self.MakeRFaccDistFile.upper() == "TRUE":
            self.chkrfaacDistfile.setChecked(True)

        self.chkdischarge.setChecked(False)
        if self.MakeFlowDistFile.upper() == "TRUE":
            self.chkdischarge.setChecked(True)

        self.chkPrintAveValue.setChecked(False)
        if self.PrintAveValue.upper() == "TRUE":
            self.chkPrintAveValue.setChecked(True)

        self.chklog.setChecked(False)
        if self.WriteLog.upper() == "TRUE":
            self.chklog.setChecked(True)

        if self.SimulationStartingTime == "0":
            now = QDateTime.currentDateTime()
            self.dateTimeEdit.setDateTime(now)
            self.chkStartingTime.setChecked(False)
            self.dateTimeEdit.setEnabled(False)
            self.dataTimeFormat = False
        else:
            self.chkStartingTime.setChecked(True)
            self.dateTimeEdit.setEnabled(True)
            dateTime = QDateTime.fromString(
                self.SimulationStartingTime, "yyyy-MM-dd hh:mm"
            )
            self.dateTimeEdit.setDateTime(dateTime)
            self.dataTimeFormat = True

        self.chkParallel.setChecked(False)
        if int(self.MaxDegreeOfParallelism) > 0:
            self.chkParallel.setChecked(True)

        if self.ComputationalTimeStep_min is not None:
            intvalue = int(self.ComputationalTimeStep_min)
            self.spTimeStep_min.setValue(intvalue)
        else:
            if self._xsize <= 200:
                value = 3
            elif self._xsize > 200:
                value = 5
            self.spTimeStep_min.setValue(value)

        if self.MaxDegreeOfParallelism is not None:
            intvalue = int(self.MaxDegreeOfParallelism)
            self.spTimeStep_min_2.setValue(intvalue)

        if self.AveValueTimeInterval_min:
            self.spbAveValueTimeInterval_min.setValue(
                int(self.AveValueTimeInterval_min)
            )

        if self.OutputTimeStep_min is not None and self.OutputTimeStep_min != "":
            self.txtOutput_time_step.setText(str(self.OutputTimeStep_min))

        self.txtSimulation_duration.setText("")
        if self.SimulationDuration_hr is not None:
            self.txtSimulation_duration.setText(self.SimulationDuration_hr)

        if self.OutputTimeStep_min is not None:
            self.txtOutput_time_step.setText(self.OutputTimeStep_min)

        # 체크 박스 셋팅 (프로젝트 파일에서 체크 값 받아서 셋팅)
        self.chkInfiltration.setChecked(True)
        if self.SimulateInfiltration and self.SimulateInfiltration.upper() != "TRUE":
            self.chkInfiltration.setChecked(False)

        self.chkSubsurfaceFlow.setChecked(True)
        if (
            self.SimulateSubsurfaceFlow
            and self.SimulateSubsurfaceFlow.upper() != "TRUE"
        ):
            self.chkSubsurfaceFlow.setChecked(False)

        self.chkBaseFlow.setChecked(True)
        if self.SimulateBaseFlow and self.SimulateBaseFlow.upper() != "TRUE":
            self.chkBaseFlow.setChecked(False)

        self.chkInterception.setChecked(True)
        if self.SimulateInterception and self.SimulateInterception.upper() != "TRUE":
            self.chkInterception.setChecked(False)

        self.chkEvapotranspiration.setChecked(True)
        if (
            self.SimulateEvapotranspiration
            and self.SimulateEvapotranspiration.upper() != "TRUE"
        ):
            self.chkEvapotranspiration.setChecked(False)

        self.chkSnowMelt.setChecked(True)
        if self.SimulateSnowMelt and self.SimulateSnowMelt.upper() != "TRUE":
            self.chkSnowMelt.setChecked(False)

        if self.SimulateFlowControl is not None:
            if self.SimulateFlowControl.upper() == "TRUE":
                self.chkFlowControl.setChecked(True)

        self.chkStartingTime.stateChanged.connect(self.Check_StartingTime)

        self.chkmakeimage.stateChanged.connect(self.MakeASC_IMAGE)
        self.chkmakeASC.stateChanged.connect(self.MakeASC_IMAGE)
        self.MakeASC_IMAGE()

        if self.IsFixedTimeStep.upper() == "TRUE":
            self.chkfixeTimeStep.setChecked(True)

    def printcombo(self):
        if self.cmbPrint.currentText() == "All":
            self.chkmakeimage.setEnabled(True)
            self.chkmakeASC.setEnabled(True)
            self.MakeASC_IMAGE()
        else:
            self.chkmakeimage.setEnabled(False)
            self.chkmakeASC.setEnabled(False)
            self.chksoiSaturation.setEnabled(False)
            self.chkrfDistFile.setEnabled(False)
            self.chkrfaacDistfile.setEnabled(False)
            self.chkdischarge.setEnabled(False)

    def check_simulate_option(self, state: bool, q_widget_list: List[QWidget]):
        for q_widget in q_widget_list:
            q_widget.setEnabled(state)

    def SPvaluechange(self):
        value = self.spTimeStep_min_2.text()
        if value == "0":
            MsError(" Input 0 can not be input. ")

    def Check_Parallel(self):
        flag = self.chkParallel.isChecked()
        self.spTimeStep_min_2.setEnabled(flag)

    def Check_Ave_Value_Time(self):
        flag = self.chkPrintAveValue.isChecked()
        self.label_19.setEnabled(flag)
        self.spbAveValueTimeInterval_min.setEnabled(flag)

    def Check_Flow(self, flag):
        self.chkAutoROM.setEnabled(flag)
        self.chkAutoROM.setChecked(False)

    def Check_StartingTime(self):
        flag = self.chkStartingTime.isChecked()
        self.dateTimeEdit.setEnabled(flag)
        self.dataTimeFormat = flag

    def MakeASC_IMAGE(self):
        flag = self.chkmakeimage.isChecked() or self.chkmakeASC.isChecked()
        self.chksoiSaturation.setEnabled(flag)
        self.chkrfDistFile.setEnabled(flag)
        self.chkrfaacDistfile.setEnabled(flag)
        self.chkdischarge.setEnabled(flag)

    # ======================WatchPoint Tab Table Setting and btn event =========================
    def Set_Wathpoint_tab_default(self):
        try:
            # 테이블 상에 선택된 열을 위로 올림
            self.btnMoveup.clicked.connect(self.MoveUp)

            # 테이블 상에 선택된 열을 아래로 내림
            self.btnMovedown.clicked.connect(self.MoveDown)

            # 테이블 상에 선택된 열을 삭제
            self.btnRemove.clicked.connect(self.ReMove)

            # 테이블 셀값을 변경 불가능 하게 설정
            self.tbList.setEditTriggers(QAbstractItemView.NoEditTriggers)

            # color picker 이벤트
            self.btnColorPicker.clicked.connect(
                lambda: self.color_picker(self.btnColorPicker)
            )
            self.btnColorPicker_3.clicked.connect(
                lambda: self.color_picker(self.btnColorPicker_3)
            )

            # 2017/11/22-------------------
            # 테이블 셀 값 선택한 값의 위치로 view 이동
            #             self.btnGrid.clicked.connect(self.GoToGrid)
            self.btnGrid.clicked.connect(lambda: self.btnGotoGrid(self.tbList))

            # 테이블 셀값을 변경 가능하게 설정 ----> 색상값 변경임 잘못된 구현 변경 해야함
            self.btnEdit.clicked.connect(self.Edit)

            self.btnAddSelectCell.clicked.connect(self.Add_Selected_Cell)

            # 최하류 셀 넣기
            self.btnAddMostDown.clicked.connect(self.Add_MostDown_Stream)

            # 각각의 컬럼에 갑셋팅(xml 상에 'ObTSId', 'ObTSLegend', 'ObTSMissingCount' 항목의 값이 없음
            self.Watchpoint_TableCreate(len(self.Name))
            self.Watchpoint_Table_Insert()
        except Exception as wa:
            MsError(wa)

    def MoveUp(self):
        row = self.tbList.currentRow()
        column = self.tbList.currentColumn()
        if row > 0:
            self.tbList.insertRow(row - 1)
            for i in range(self.tbList.columnCount()):
                self.tbList.setItem(row - 1, i, self.tbList.takeItem(row + 1, i))
                self.tbList.setCurrentCell(row - 1, column)
            self.tbList.removeRow(row + 1)

    def MoveDown(self):
        row = self.tbList.currentRow()
        column = self.tbList.currentColumn()
        if row >= 0:
            if row < self.tbList.rowCount() - 1:
                self.tbList.insertRow(row + 2)
                for i in range(self.tbList.columnCount()):
                    self.tbList.setItem(row + 2, i, self.tbList.takeItem(row, i))
                    self.tbList.setCurrentCell(row + 2, column)
                self.tbList.removeRow(row)

    def check_add_watchpoint(self, x, y, name):
        rowCount = self.tbList.rowCount()
        self.RetBool = True
        for row in range(0, rowCount):
            Names = self.tbList.item(row, 0).text()
            X = self.tbList.item(row, 1).text()
            Y = self.tbList.item(row, 2).text()
            if (X == str(x) and Y == str(y)) or name == Names:
                self.RetBool = False
        return self.RetBool

    def ReMove(self):
        row = self.tbList.currentIndex().row()
        mess = "Are you sure you want to delete the selected items?"
        result = QMessageBox.question(
            None, "Watershed Setup", mess, QMessageBox.Yes, QMessageBox.No
        )
        if result == QMessageBox.Yes:
            self.tbList.removeRow(row)

        self.post_grid_remove2()
        if self.chkFlowContorGird.isChecked():
            self.FlowContorGird_paint()
        if self.chkWatch_Point.isChecked():
            if self.tbList.rowCount() != 0:
                self.watchpoint_paint()

    def btnGotoGrid(self, tbl):
        row = tbl.currentRow()
        if row > -1:
            ColX = int(tbl.item(row, 1).text())
            RowY = int(tbl.item(row, 2).text())

            self.post_grid_remove()
            self.mapcanvas.refresh()
            self.scale_changed_mapcanvas()
            self.row_cols_grid(ColX, RowY, None)
            self.tool.scale_changed_disconnect()
        else:
            MsInfo("Check! select row")

    def CheckTableValue(self, x, y):
        rowCount = self.tbList.rowCount()
        self.RetBool = True
        for row in range(0, rowCount):
            X = self.tbList.item(row, 1).text()
            Y = self.tbList.item(row, 2).text()
            if X == str(x) and Y == str(y):
                self.RetBool = False
        return self.RetBool

    # 에디트 클릭시에 선택된 Row 의 name 변경
    def Edit(self):
        # 현재 선택된 Row
        row = self.tbList.currentRow()

        if row > -1:
            cell = self.tbList.item(row, 0).text()
            # 다이얼 로그 출력하여 사용자가 셀값 제정의
            # text, ok = QtGui.QInputDialog.getText(self, 'Input Dialog','Enter name:',QLineEdit.Normal,cell)
            text, ok = QInputDialog.getText(
                self, "Input Dialog", "Enter name:", QLineEdit.Normal, cell
            )
            if ok:
                item = QTableWidgetItem(str(text))  # create a new Item
                self.tbList.setItem(row, 0, item)
        else:
            MsInfo("check! select Row")

    # 2017 -12-15 박: 추가 버튼 눌렀을때 Watchpoint table 에 데이터 추가 하기
    def Add_Selected_Cell(self):
        try:
            if self.tool._FXCOL != 0 and self.tool._FYROW != 0:
                rowCount = self.tbList.rowCount()
                if rowCount > 0:
                    text, ok = QInputDialog.getText(
                        self, "Input Dialog", "Enter name:", QLineEdit.Normal, ""
                    )
                    if text.strip() != "":
                        if self.check_add_watchpoint(
                            self.tool._YROW, self.tool._XCOL, text
                        ):
                            self.tbList.insertRow(rowCount)
                            self.tbList.setItem(rowCount, 0, QTableWidgetItem(text))
                            self.tbList.setItem(
                                rowCount, 1, QTableWidgetItem(str(self.tool._FYROW))
                            )
                            self.tbList.setItem(
                                rowCount, 2, QTableWidgetItem(str(self.tool._FXCOL))
                            )
                            self.ColX.append(self.tool._FXCOL)
                            self.RowY.append(self.tool._FYROW)
                            if self.chkWatch_Point.isChecked():
                                self.row_cols_grid(
                                    self.tool._FYROW, self.tool._FXCOL, "watchpoint"
                                )
                        else:
                            MsInfo(" Name or watchpoint is required. ")
                    else:
                        MsInfo(" Name is required. ")
                else:
                    text, ok = QInputDialog.getText(
                        self, "Input Dialog", "Enter name:", QLineEdit.Normal, ""
                    )
                    if text.strip() != "":
                        self.tbList.insertRow(0)
                        self.tbList.setItem(rowCount, 0, QTableWidgetItem(text))
                        self.tbList.setItem(
                            0, 1, QTableWidgetItem(str(self.tool._FYROW))
                        )
                        self.tbList.setItem(
                            0, 2, QTableWidgetItem(str(self.tool._FXCOL))
                        )
                        self.ColX.append(self.tool._FXCOL)
                        self.RowY.append(self.tool._FYROW)
                        if self.chkWatch_Point.isChecked():
                            self.row_cols_grid(
                                self.tool._FYROW, self.tool._FXCOL, "watchpoint"
                            )
                    else:
                        MsInfo(" Name is required. ")
        except Exception as e:
            MsError(e)

    def Add_MostDown_Stream(self):
        if len(self._StreamWSID) == 1:
            x = self._wsinfo.facMaxCellxCol
            y = self._wsinfo.facMaxCellyRow

            rowCount = self.tbList.rowCount()
            if self.CheckTableValue(x, y):
                self.tbList.insertRow(rowCount)
                text, ok = QInputDialog.getText(
                    self, "Input Dialog", "Enter name:", QLineEdit.Normal, ""
                )
                self.tbList.setItem(rowCount, 0, QTableWidgetItem(text))
                self.tbList.setItem(rowCount, 1, QTableWidgetItem(str(x)))
                self.tbList.setItem(rowCount, 2, QTableWidgetItem(str(y)))
                self.row_cols_grid(x, y, "watchpoint")
                for id in range(len(self._StreamWSID)):
                    self.SetMostDownStream(self._StreamWSID[id])
            else:
                MsInfo(" The most downstream value already exists. ")
        else:
            # 최박사님이 문구 주실거임
            # 2018-07-24 박: 최하류 유역이 1개일때만 자동 추가 2개 이상일때는 추가하지 않고 문구로 대체함
            MsInfo(
                " The number of most down stream cells are more than 1."
                + "\r\n"
                + " Add most down stream cells manually. "
            )

    def Watchpoint_TableCreate(self, Row):
        self.tbList.setColumnCount(3)
        self.tbList.setRowCount(Row)
        self.tbList.setHorizontalHeaderLabels(["Name", "ColX", "RowY"])
        # 테이블 넓이 에 맞게 Name 항목 넓이 지정
        self.tbList.setColumnWidth(0, 176)

    # watchpoint datault 값을 변수에 저장
    def Set_Wathpoint_default_value(self):
        self.Name = []
        self.ColX = []
        self.RowY = []
        if self._WatchPointCount == 0:
            # Dll 에서 X,Y 값을 넣었을때 받는 값

            # 2020-05-19 박: 기존에서 함수명 변경됨
            x = self._wsinfo.facMaxCellxCol
            y = self._wsinfo.facMaxCellyRow

            # 2018-07-24 박: 처음 로드시 최하류 셀이 1개이면 추가함 그이상이면 추가하지 안음
            if self._wsinfo.mostDownStreamWSCount == 1:
                names = "MD"
                self.Name.append(names)
                self.ColX.append(str(x))
                self.RowY.append(str(y))
                # New Project 일때 프로그램 최하류 정보를 Dll에 넣음

                for id in range(self._wsinfo.mostDownStreamWSCount):
                    self.SetMostDownStream(self._StreamWSID[id])

        elif self._WatchPointCount > 1:
            for flowitem in self._xmltodict["GRMProject"]["WatchPoints"]:
                self.ColX.append(str(flowitem["ColX"]))
                self.RowY.append(str(flowitem["RowY"]))
                self.Name.append(flowitem["Name"])

        elif self._WatchPointCount == 1:
            self.ColX.append(str(self._xmltodict["GRMProject"]["WatchPoints"]["ColX"]))
            self.RowY.append(str(self._xmltodict["GRMProject"]["WatchPoints"]["RowY"]))
            self.Name.append(str(self._xmltodict["GRMProject"]["WatchPoints"]["Name"]))

    def Watchpoint_Table_Insert(self):
        if len(self.Name) > 0:
            for i in range(0, len(self.Name)):
                # 사용자에게 CVID 표출 안함
                self.tbList.setItem(i, 0, QTableWidgetItem(self.Name[i]))
                self.tbList.setItem(i, 1, QTableWidgetItem(self.ColX[i]))
                self.tbList.setItem(i, 2, QTableWidgetItem(self.RowY[i]))

    # 색상 변경 Picker -- 2017/09/07  조가 주석달음
    def color_picker(self, bttom):  # , type
        color = QColorDialog.getColor()
        bttom.setStyleSheet("background-color:" + str(color.name()) + ";")

        self.post_grid_remove2()
        self.watchpoint()
        self.click_FlowContorGird()

    # watchpoint RubberBand 제거
    def post_grid_remove2(self):
        for v in self.canvasRubberBand:
            #         for v in self.mapcanvas.scene().items():
            if issubclass(type(v), QgsRubberBand) == True:
                self.mapcanvas.scene().removeItem(v)

    def watchpoint(self):
        if self.chkWatch_Point.isChecked():
            self.watchpoint_paint()
        else:
            # 지우기
            self.post_grid_remove2()
            if self.chkFlowContorGird.isChecked():
                self.FlowContorGird_paint()

    def watchpoint_paint(self):
        try:
            if len(self.ColX) > 0 and len(self.RowY) > 0:
                if self.tbList.rowCount() > 0:
                    for i in range(0, self.tbList.rowCount()):
                        x = self.tbList.item(i, 1).text()
                        y = self.tbList.item(i, 2).text()
                        self.row_cols_grid(int(x), int(y), "watchpoint")

                else:
                    for i in range(0, len(self.ColX)):
                        self.row_cols_grid(
                            int(self.ColX[i]), int(self.RowY[i]), "watchpoint"
                        )
        except Exception as e:
            MsError(e)

    # 1. row/cols로 마커
    def row_cols_grid(self, row, column, type):
        if str(row) != "" and str(column) != "":
            row = int(row)
            column = int(column)
            if row < 0 or column < 0 or self._height <= column or self._width <= row:
                row = "out of extent"
                column = "out of extent"
                MsInfo("{0}, {1}".format(str(row), str(column)))
            else:
                if type == "watchpoint":
                    Cell_X_Center2 = self._xmin + self._xsize / 2 + self._xsize * (row)
                    Cell_Y_Center2 = (
                        self._ymax - self._ysize / 2 - self._ysize * (column)
                    )
                    if (
                        Cell_X_Center2 <= self._xmax
                        or self._xmin <= Cell_X_Center2
                        or Cell_Y_Center2 <= self._ymax
                        or self._ymin <= Cell_Y_Center2
                    ):
                        self.draw_grid2(
                            Cell_X_Center2, Cell_Y_Center2, self.btnColorPicker
                        )

                else:
                    self.lblColRow.setText(
                        "xCol, yRow:" + str(row) + " , " + str(column)
                    )
                    self.tool.Cell_X_Center = (
                        self._xmin + self._xsize / 2 + self._xsize * (row)
                    )
                    self.tool.Cell_Y_Center = (
                        self._ymax - self._ysize / 2 - self._ysize * (column)
                    )
                    if (
                        self.tool.Cell_X_Center <= self._xmax
                        or self.xmin <= self.tool.Cell_X_Center
                        or self.tool.Cell_Y_Center <= self._ymax
                        or self._ymin <= self.tool.Cell_Y_Center
                    ):
                        oldExtent = self.mapcanvas.extent()

                        x1n = self.tool.Cell_X_Center - oldExtent.width() / 2.0
                        x2n = self.tool.Cell_X_Center + oldExtent.width() / 2.0
                        y1n = self.tool.Cell_Y_Center - oldExtent.height() / 2.0
                        y2n = self.tool.Cell_Y_Center + oldExtent.height() / 2.0

                        self.mapcanvas.setExtent(QgsRectangle(x1n, y2n, x2n, y1n))
                        self.draw_grid(self.tool.Cell_X_Center, self.tool.Cell_Y_Center)
        else:
            MsError("There is a problem with the text value.")
            return

    # Watch point 그림을 Rubberbanc로 처리 함
    def draw_grid2(self, x, y, btn):
        r = QgsRubberBand(self.mapcanvas, True)
        size = self._xsize / 2

        points = [
            [
                QgsPointXY(x - size, y + size),
                QgsPointXY(x - size, y - size),
                QgsPointXY(x + size, y - size),
                QgsPointXY(x + size, y + size),
            ]
        ]

        r.setToGeometry(QgsGeometry.fromPolygonXY(points), None)
        r.setColor(QColor(btn.palette().button().color()))
        r.setWidth(2)

        self.canvasRubberBand.append(r)

    def click_FlowContorGird(self):
        if self.chkFlowContorGird.isChecked():
            self.FlowContorGird_paint()
        else:
            # 지우기
            self.post_grid_remove2()
            if self.chkWatch_Point.isChecked():
                self.watchpoint_paint()

    def FlowContorGird_paint(self):
        counts = self.tlbFlowControl.rowCount()
        for i in range(0, counts):
            xvalue = (
                self._xmin
                + self._xsize / 2
                + self._xsize * (int(self.tlbFlowControl.item(i, 1).text()))
            )
            yvalue = (
                self._ymax
                - self._ysize / 2
                - self._ysize * (int(self.tlbFlowControl.item(i, 2).text()))
            )
            self.draw_grid2(xvalue, yvalue, self.btnColorPicker_3)

    # 그리드 라인 함수
    def show_hide_grid_line(self):
        if self.show_grid_line.isChecked():
            self.add_grid_layer()
        else:
            self.remove_grid_layer()

    def remove_grid_layer(self):
        self.grid_line.setOpacity(0)
        self.mapcanvas.refresh()

    # 플로우 디렉션
    def show_hide_flow_direction(self):
        if self.show_flow_direction.isChecked():
            self.show_flow_directions()
        else:
            self.hide_flow_direction()

    def add_grid_layer(self):
        names = [layer.name() for layer in QgsProject.instance().mapLayers().values()]
        if names.count("grid_line") > 0:
            self.grid_line.setOpacity(1)
            self.mapcanvas.refresh()
            if names.count("flow_layer") > 0:
                # self.mapcanvas.setLayers([self.flow_direction_layer,self.grid_line,self.layer])
                self.mapcanvas.setLayers(
                    [
                        self.flow_direction,
                        self.grid_line,
                        self.layer,
                        self.Wsid_label_shape,
                    ]
                )
        else:
            self.grid_line = get_point_layer(self.layer, self.mapcanvas)
            QgsProject.instance().addMapLayer(self.grid_line, False)
            self.layer.extent().combineExtentWith(self.grid_line.extent())
            self.mapcanvas.setExtent(self.mapcanvas.extent())

            # ========= 2017/11/10 : 기본적으로 Grid line 단일 체크시 Grid line 만 표현,flow direction 체크 시 flow direction 함께 표시
            self.mapcanvas.setLayers(
                [self.grid_line, self.layer, self.Wsid_label_shape]
            )

            if self.flow_direction:
                self.mapcanvas.setLayers(
                    [
                        self.flow_direction,
                        self.grid_line,
                        self.layer,
                        self.Wsid_label_shape,
                    ]
                )

    def show_flow_directions(self):
        names = [layer.name() for layer in QgsProject.instance().mapLayers().values()]
        if names.count("flow_layer") > 0:
            self.flow_direction.setOpacity(1)
            self.mapcanvas.refresh()
        else:
            FD = self._xmltodict["GRMProject"]["ProjectSettings"]["FlowDirectionFile"]
            ST = self._xmltodict["GRMProject"]["ProjectSettings"]["StreamFile"]
            self.layer2 = QgsRasterLayer(FD, "FD", "gdal")
            self.layer3 = QgsRasterLayer(ST, "ST", "gdal")

            strFDType = self._xmltodict["GRMProject"]["ProjectSettings"][
                "FlowDirectionType"
            ]
            self.flow_direction = get_flow_layer(
                self.layer2, self.mapcanvas, self.layer3, strFDType, self.GridCellSize
            )

            #  신규 소스
            QgsProject.instance().addMapLayer(self.flow_direction, False)
            self.layer.extent().combineExtentWith(self.flow_direction.extent())

            # ========= 2017/11/10 : 기본적으로 flow direction 단일 체크시 다음 flow direction 만 표현,Grid line 체크 시 grid line 함께 표시
            self.mapcanvas.setLayers(
                [self.flow_direction, self.layer, self.Wsid_label_shape]
            )
            if names.count("grid_line") > 0:
                self.mapcanvas.setLayers(
                    [
                        self.grid_line,
                        self.flow_direction,
                        self.layer,
                        self.Wsid_label_shape,
                    ]
                )
            # ========= 2017/11/10 : 기본적으로 flow direction 단일 체크시 다음 flow direction 만 표현,Grid line 체크 시 grid line 함께 표시

    # Qdilog 창에 Qtablewidget 셋팅
    def aboutApp(self):
        website = "http://code.google.com/p/comictagger"
        msgBox = QMessageBox()
        msgBox.setWindowTitle(self.tr("Move to grid"))
        msgBox.setTextFormat(Qt.RichText)

        msgBox.setText("<pre></pre>")
        self.addGroupWidget(msgBox)
        ret = msgBox.exec_()

    # Create TableWidget
    def addGroupWidget(self, parentItem):
        # 라디오 버튼, move to grid, xCol No, yRow No
        self.rdo_xColyRowNo = QRadioButton("xCol No, yRow No", parentItem)
        self.rdo_xy = QRadioButton("x, y", parentItem)

        # 텍스트 박스
        self.txt_xColyRowNo_1 = QLineEdit(parentItem)
        self.txt_xColyRowNo_2 = QLineEdit(parentItem)
        self.txt_xy1 = QLineEdit(parentItem)
        self.txt_xy2 = QLineEdit(parentItem)
        self.btn_Cancel = QPushButton(parentItem)
        self.btn_Cancel.setText("Cancel")

        self.btn_OK = QPushButton(parentItem)
        self.btn_OK.setText("OK")
        # 위치 정의 setGeometry(x,y,w,h)
        layout = parentItem.layout()

        layout.addWidget(self.rdo_xColyRowNo, 0, 0)
        layout.addWidget(self.rdo_xy, 1, 0)
        layout.addWidget(self.txt_xColyRowNo_1, 0, 1)
        layout.addWidget(self.txt_xColyRowNo_2, 0, 2)
        layout.addWidget(self.txt_xy1, 1, 1)
        layout.addWidget(self.txt_xy2, 1, 2)

        layout.addWidget(self.btn_Cancel, 2, 2)
        layout.addWidget(self.btn_OK, 2, 1)

        self.txt_xColyRowNo_1.setMaximumWidth(100)
        self.txt_xColyRowNo_2.setMaximumWidth(100)
        self.txt_xy1.setFixedWidth(100)
        self.txt_xy2.setFixedWidth(100)

        # 버튼별 이벤트
        # 1. rdo_xColyRowNo가 체크 시 그 외 비활성화
        self.rdo_xColyRowNo.setChecked(True)
        self.rdo_xy.setChecked(False)
        self.txt_xy1.setDisabled(True)
        self.txt_xy2.setDisabled(True)
        # 라디오 버튼 이벤트, 함수는 나중에 수정 바람... 2017/10/19 Cho
        self.rdo_xColyRowNo.clicked.connect(self.disableFunction)
        self.rdo_xy.clicked.connect(self.disableFunction)
        self.btn_OK.clicked.connect(self.OK_Click)
        self.btn_Cancel.clicked.connect(lambda: self.Cancel_Click(parentItem))

    def Cancel_Click(self, parentItem):
        parentItem.close()

    # 폼 종료
    def Close_Form(self):
        self.close()

    def closeEvent(self, event):
        del self._wsinfo
        self.Clear_Canvas()
        self.closeDialogEvent.emit()

    def SaveProject(self, flag=False):
        self.InputDictionary()
        DictoXml = unparse(self._xmltodict)
        fw = open(self.ProjectFile, "w+")
        fw.write(DictoXml)
        fw.close()

        # 2020-02-10 박: XML 체크할때 Landcover 데이터를 배열에 받아서 반환 함
        _XmlCheck.Check_Gmp_xml(self.ProjectFile)
        self._LandCoverCount = _XmlCheck._LandCoverCount
        self._GreenAmptCount = _XmlCheck._GreenAmptCount
        self._SoilDepthCount = _XmlCheck._SoilDepthCount
        self._WatchPointCount = _XmlCheck._WatchPointCount
        self._SubWatershedCount = _XmlCheck._SubWatershedCount
        self._FlowControlCount = _XmlCheck._FlowControlCount
        self._ChannelSettingsCount = _XmlCheck._ChannelSettingsCount
        if flag:
            MsInfo("[" + self.ProjectFile + "]" + " was saved. ")

    def InputDictionary(self):
        try:
            # =========================simulation tab ===================================
            self._xmltodict["GRMProject"]["ProjectSettings"][
                "ComputationalTimeStep_min"
            ] = self.spTimeStep_min.text()
            if self.chkStartingTime.isChecked():
                DateTime = self.dateTimeEdit.dateTime().toString("yyyy-MM-dd hh:mm")
                self._xmltodict["GRMProject"]["ProjectSettings"][
                    "SimulationStartingTime"
                ] = DateTime
            else:
                self._xmltodict["GRMProject"]["ProjectSettings"][
                    "SimulationStartingTime"
                ] = "0"

            if self.chkParallel.isChecked():
                self._xmltodict["GRMProject"]["ProjectSettings"][
                    "MaxDegreeOfParallelism"
                ] = self.spTimeStep_min_2.text()

            else:
                self._xmltodict["GRMProject"]["ProjectSettings"][
                    "MaxDegreeOfParallelism"
                ] = "-1"

            if self.chkPrintAveValue.isChecked():
                self._xmltodict["GRMProject"]["ProjectSettings"][
                    "AveValueTimeInterval_min"
                ] = self.spbAveValueTimeInterval_min.text()
            else:
                self._xmltodict["GRMProject"]["ProjectSettings"][
                    "AveValueTimeInterval_min"
                ] = ""

            self._xmltodict["GRMProject"]["ProjectSettings"][
                "OutputTimeStep_min"
            ] = self.txtOutput_time_step.text()
            self._xmltodict["GRMProject"]["ProjectSettings"][
                "SimulationDuration_hr"
            ] = self.txtSimulation_duration.text()
            self._xmltodict["GRMProject"]["ProjectSettings"][
                "OutputTimeStep_min"
            ] = self.txtOutput_time_step.text()

            projectTagDic = {
                "SimulateInfiltration": self.chkInfiltration,
                "SimulateSubsurfaceFlow": self.chkSubsurfaceFlow,
                "SimulateBaseFlow": self.chkBaseFlow,
                "SimulateInterception": self.chkInterception,
                "SimulateEvapotranspiration": self.chkEvapotranspiration,
                "SimulateSnowMelt": self.chkSnowMelt,
                "SimulateFlowControl": self.chkFlowControl,
                "MakeIMGFile": self.chkmakeimage,
                "MakeASCFile": self.chkmakeASC,
                "MakeSoilSaturationDistFile": self.chksoiSaturation,
                "MakeRfDistFile": self.chkrfDistFile,
                "MakeRFaccDistFile": self.chkrfaacDistfile,
                "MakeFlowDistFile": self.chkdischarge,
                "PrintAveValue": self.chkPrintAveValue,
                "WriteLog": self.chklog,
                "IsFixedTimeStep": self.chkfixeTimeStep,
            }

            for k in projectTagDic.keys():
                self._xmltodict["GRMProject"]["ProjectSettings"][k] = str(
                    projectTagDic[k].isChecked()
                ).lower()  #'true' or 'false'

            self._xmltodict["GRMProject"]["ProjectSettings"][
                "PrintOption"
            ] = self.cmbPrint.currentText()

            # =========================simulation tab end ===============================================

            # =========================Watch Point tab===================================================
            #     GRM._WatchPointCount
            #             if self._WatchPointCount > 0:
            try:
                # 2021.12.07 동 : watchpoint, subwatershed 태그는 Set_ProjectDataInit 함수에서 초기값 세팅을 안해주기 때문에
                # 프로젝트 오픈후 처음으로 run dialog를 실행 시켰을 때 self._WatchPointCount..등 값이 무조건 0 값으로 표기됨.
                # 그래서  값이 중복되서 저장되는 현상이 있어 keyerror가 발생하지 않는한, 무조건 적으로 지우도록 변경
                del self._xmltodict["GRMProject"]["WatchPoints"]
            except KeyError:
                pass
            self._WatchPointCount = self.tbList.rowCount()

            DictoXml = unparse(self._xmltodict)
            ET.register_namespace("", "http://tempuri.org/GRMProject.xsd")
            xmltree = ET.ElementTree(ET.fromstring(DictoXml))
            root = xmltree.getroot()

            wcount = self.tbList.rowCount()
            self._WatchPointCount = wcount
            for row in range(0, wcount):
                child = ET.Element("WatchPoints")
                root.append(child)

                WathchName = ET.Element("Name")
                WathchName.text = self.tbList.item(row, 0).text()
                child.append(WathchName)

                WathchColX = ET.Element("ColX")
                WathchColX.text = self.tbList.item(row, 1).text()
                child.append(WathchColX)

                WathchRowY = ET.Element("RowY")
                WathchRowY.text = self.tbList.item(row, 2).text()
                child.append(WathchRowY)
            xmltree_string = ET.tostring(xmltree.getroot())
            docs = dict(parse(xmltree_string))
            self._xmltodict.clear()
            self._xmltodict.update(docs)

            # =========================Wahch Point tab end===============================================

            # =========================Channel CS tab====================================================
            # 2020-04-28 박: 이부분이 따로 떨어져서 xml 생성됨 그래서 주석 처리로 변경 하고 XML 부분 수정으로 소스 수정
            if self._ChannelSettingsCount > 0:
                del self._xmltodict["GRMProject"]["ChannelSettings"]

            DictoXml = unparse(self._xmltodict)
            ET.register_namespace("", "http://tempuri.org/GRMProject.xsd")
            xmltree = ET.ElementTree(ET.fromstring(DictoXml))
            root = xmltree.getroot()
            self._ChannelSettingsCount = len(self._StreamWSID)

            for index in range(0, self._ChannelSettingsCount):
                child = ET.Element("ChannelSettings")
                root.append(child)

                WSID = ET.Element("WSID")
                WSID.text = str(self._StreamWSID[index])
                child.append(WSID)

                CrossSectionType = ET.Element("CrossSectionType")
                if self.CrossSectionType[index] == "CSCOMPOUND":
                    CrossSectionType.text = "CSCompound"
                elif self.CrossSectionType[index] == "CSSINGLE":
                    CrossSectionType.text = "CSSingle"
                else:
                    CrossSectionType.text = "CSSingle"
                child.append(CrossSectionType)

                SingleCSChannelWidthType = ET.Element("SingleCSChannelWidthType")
                if self.SingleCSChannelWidthType[index].upper() == "CWGENERATION":
                    SingleCSChannelWidthType.text = "CWGeneration"
                elif self.SingleCSChannelWidthType[index].upper() == "CWEQUATION":
                    SingleCSChannelWidthType.text = "CWEquation"
                else:
                    SingleCSChannelWidthType.text = "CWGeneration"

                child.append(SingleCSChannelWidthType)

                ChannelWidthEQc = ET.Element("ChannelWidthEQc")
                ChannelWidthEQc.text = str(self.ChannelWidthEQc[index])
                child.append(ChannelWidthEQc)

                ChannelWidthEQd = ET.Element("ChannelWidthEQd")
                ChannelWidthEQd.text = str(self.ChannelWidthEQd[index])
                child.append(ChannelWidthEQd)

                ChannelWidthEQe = ET.Element("ChannelWidthEQe")
                ChannelWidthEQe.text = str(self.ChannelWidthEQe[index])
                child.append(ChannelWidthEQe)

                ChannelWidthMostDownStream = ET.Element("ChannelWidthMostDownStream")
                ChannelWidthMostDownStream.text = str(
                    self.ChannelWidthMostDownStream[index]
                )
                child.append(ChannelWidthMostDownStream)

                LowerRegionHeight = ET.Element("LowerRegionHeight")
                LowerRegionHeight.text = str(self.LowerRegionHeight[index])
                child.append(LowerRegionHeight)

                LowerRegionBaseWidth = ET.Element("LowerRegionBaseWidth")
                LowerRegionBaseWidth.text = str(self.LowerRegionBaseWidth[index])
                child.append(LowerRegionBaseWidth)

                UpperRegionBaseWidth = ET.Element("UpperRegionBaseWidth")
                UpperRegionBaseWidth.text = str(self.UpperRegionBaseWidth[index])
                child.append(UpperRegionBaseWidth)

                CompoundCSChannelWidthLimit = ET.Element("CompoundCSChannelWidthLimit")
                CompoundCSChannelWidthLimit.text = str(
                    self.CompoundCSChannelWidthLimit[index]
                )
                child.append(CompoundCSChannelWidthLimit)

                BankSideSlopeRight = ET.Element("BankSideSlopeRight")
                BankSideSlopeRight.text = str(self.BankSideSlopeRight[index])
                child.append(BankSideSlopeRight)

                BankSideSlopeLeft = ET.Element("BankSideSlopeLeft")
                BankSideSlopeLeft.text = str(self.BankSideSlopeLeft[index])
                child.append(BankSideSlopeLeft)

            xmltree_string = ET.tostring(xmltree.getroot())
            docs = dict(parse(xmltree_string))
            self._xmltodict.clear()
            self._xmltodict.update(docs)

            # =========================Channel CS tab end================================================
            # =========================Flow Control Tab==================================================
            self.UpdateFlowControl()

            # =========================Flow Control Tab end ==================================================
            # ========================= Watershed tab ========================================================
            #             if self._SubWatershedCount>0:
            try:
                del self._xmltodict["GRMProject"]["SubWatershedSettings"]
            except KeyError:
                pass

            DictoXml = unparse(self._xmltodict)
            ET.register_namespace("", "http://tempuri.org/GRMProject.xsd")
            xmltree = ET.ElementTree(ET.fromstring(DictoXml))
            root = xmltree.getroot()
            self._SubWatershedCount = self.cb_selectws.count()
            scount = self.cb_selectws.count()

            for row in range(0, scount):
                selectWS = self.cb_selectws.itemText(row)

                child = ET.Element("SubWatershedSettings")
                root.append(child)

                ID = ET.Element("ID")
                ID.text = selectWS
                child.append(ID)

                IniSaturation = ET.Element("IniSaturation")
                IniSaturation.text = ex_to_float(
                    self._wsinfo.subwatershedPars(int(selectWS)).iniSaturation
                )
                child.append(IniSaturation)

                MinSlopeOF = ET.Element("MinSlopeOF")
                MinSlopeOF.text = ex_to_float(
                    self._wsinfo.subwatershedPars(int(selectWS)).minSlopeOF
                )
                child.append(MinSlopeOF)

                UnsaturatedKType = ET.Element("UnsaturatedKType")
                UnsaturatedKType_int = str(
                    self._wsinfo.subwatershedPars(int(selectWS)).unSatKType
                )
                UnsturatedType = "Linear"  # 2021.12.06 동  : 1 or default 값은 Linear
                if UnsaturatedKType_int == "0":
                    UnsturatedType = "Constant"
                elif UnsaturatedKType_int == "2":
                    UnsturatedType = "Exponential"

                UnsaturatedKType.text = UnsturatedType
                child.append(UnsaturatedKType)

                CoefUnsaturatedK = ET.Element("CoefUnsaturatedK")
                CoefUnsaturatedK.text = ex_to_float(
                    self._wsinfo.subwatershedPars(int(selectWS)).coefUnsaturatedK
                )
                child.append(CoefUnsaturatedK)

                MinSlopeChBed = ET.Element("MinSlopeChBed")
                MinSlopeChBed.text = ex_to_float(
                    self._wsinfo.subwatershedPars(int(selectWS)).minSlopeChBed
                )
                child.append(MinSlopeChBed)

                MinChBaseWidth = ET.Element("MinChBaseWidth")
                MinChBaseWidth.text = ex_to_float(
                    self._wsinfo.subwatershedPars(int(selectWS)).minChBaseWidth
                )
                child.append(MinChBaseWidth)

                ChRoughness = ET.Element("ChRoughness")
                ChRoughness.text = ex_to_float(
                    self._wsinfo.subwatershedPars(int(selectWS)).chRoughness
                )
                child.append(ChRoughness)

                DryStreamOrder = ET.Element("DryStreamOrder")
                DryStreamOrder.text = str(
                    self._wsinfo.subwatershedPars(int(selectWS)).dryStreamOrder
                )
                child.append(DryStreamOrder)

                IniFlow = ET.Element("IniFlow")
                IniFlow.text = "0"
                if self._wsinfo.subwatershedPars(int(selectWS)).iniFlow is not None:
                    IniFlow.text = ex_to_float(
                        self._wsinfo.subwatershedPars(int(selectWS)).iniFlow
                    )
                child.append(IniFlow)

                CalCoefLCRoughness = ET.Element("CalCoefLCRoughness")
                CalCoefLCRoughness.text = ex_to_float(
                    self._wsinfo.subwatershedPars(int(selectWS)).ccLCRoughness
                )
                child.append(CalCoefLCRoughness)

                CalCoefPorosity = ET.Element("CalCoefPorosity")
                CalCoefPorosity.text = ex_to_float(
                    self._wsinfo.subwatershedPars(int(selectWS)).ccPorosity
                )
                child.append(CalCoefPorosity)

                CalCoefWFSuctionHead = ET.Element("CalCoefWFSuctionHead")
                CalCoefWFSuctionHead.text = ex_to_float(
                    self._wsinfo.subwatershedPars(int(selectWS)).ccWFSuctionHead
                )
                child.append(CalCoefWFSuctionHead)

                CalCoefHydraulicK = ET.Element("CalCoefHydraulicK")
                CalCoefHydraulicK.text = ex_to_float(
                    self._wsinfo.subwatershedPars(int(selectWS)).ccHydraulicK
                )
                child.append(CalCoefHydraulicK)

                CalCoefSoilDepth = ET.Element("CalCoefSoilDepth")
                CalCoefSoilDepth.text = ex_to_float(
                    self._wsinfo.subwatershedPars(int(selectWS)).ccSoilDepth
                )
                child.append(CalCoefSoilDepth)

                InterceptionMethod = ET.Element("InterceptionMethod")
                InterceptionMethod_int = int(
                    self._wsinfo.subwatershedPars(int(selectWS)).interceptMethod
                )
                InterceptionMethodType = EnumInterceptionMethod(
                    InterceptionMethod_int
                ).name
                InterceptionMethod.text = InterceptionMethodType
                child.append(InterceptionMethod)

                PETMethod = ET.Element("PETMethod")
                PETMethod_int = int(
                    self._wsinfo.subwatershedPars(int(selectWS)).potentialETMethod
                )
                PETMethodType = EnumPETMethod(PETMethod_int).name
                PETMethod.text = PETMethodType
                child.append(PETMethod)

                ETCoef = ET.Element("ETCoef")
                ETCoef.text = ex_to_float(
                    self._wsinfo.subwatershedPars(int(selectWS)).etCoeff
                )
                child.append(ETCoef)

                SnowmeltMethod = ET.Element("SnowmeltMethod")
                SnowmeltMethod_int = int(
                    self._wsinfo.subwatershedPars(int(selectWS)).snowMeltMethod
                )
                SnowmeltMethodType = EnumSnowMeltMethod(SnowmeltMethod_int).name
                SnowmeltMethod.text = SnowmeltMethodType
                child.append(SnowmeltMethod)

                TempSnowRain = ET.Element("TempSnowRain")
                TempSnowRain.text = ex_to_float(
                    self._wsinfo.subwatershedPars(int(selectWS)).tempSnowRain
                )
                child.append(TempSnowRain)

                SnowmeltingTemp = ET.Element("SnowmeltingTemp")
                SnowmeltingTemp.text = ex_to_float(
                    self._wsinfo.subwatershedPars(int(selectWS)).smeltingTemp
                )
                child.append(SnowmeltingTemp)

                SnowCovRatio = ET.Element("SnowCovRatio")
                SnowCovRatio.text = ex_to_float(
                    self._wsinfo.subwatershedPars(int(selectWS)).snowCovRatio
                )
                child.append(SnowCovRatio)

                SnowmeltCoef = ET.Element("SnowmeltCoef")
                SnowmeltCoef.text = ex_to_float(
                    self._wsinfo.subwatershedPars(int(selectWS)).smeltCoef
                )
                child.append(SnowmeltCoef)

                UserSet = ET.Element("UserSet")
                UserSet_value = str(
                    self._wsinfo.subwatershedPars(int(selectWS)).userSet
                )
                UserSet.text = "False"
                if UserSet_value == "1":
                    UserSet.text = "True"

                child.append(UserSet)

            xmltree_string = ET.tostring(xmltree.getroot())
            docs = dict(parse(xmltree_string))
            self._xmltodict.clear()
            self._xmltodict.update(docs)

        except Exception as e:
            MsError(e)

    def Clear_Canvas(self):
        try:
            # 레이어가 자꾸 잡혀 있어서 프로세스가 사용중으로 나옴 그래서 레이어 삭제 기능 추가해서 넣음
            layers = self.mapcanvas.layers()
            for l in layers:
                QgsProject.instance().removeMapLayer(l.id())
            self.mapcanvas.clearCache()
        #             self.AddLayerQGIS()

        except Exception as e:
            pass

    def AddLayerQGIS(self):
        # dictionary 값을 받아서 레이어 목록을 Qgis 에 올림
        proTag = [
            "DomainFile",
            "SlopeFile",
            "FlowDirectionFile",
            "FlowAccumFile" "StreamFile",
            "LandCoverFile",
            "SoilDepthFile",
            "SoilTextureFile",
        ]

        for t in proTag:
            if self._xmltodict["GRMProject"]["ProjectSettings"][t] is not None:
                self.AddlayerQGIS(self._xmltodict["GRMProject"]["ProjectSettings"][t])

    # gis에 올리기
    def AddlayerQGIS(self, path):
        try:
            if os.path.isfile(path):
                fileInfo = QFileInfo(path)
                baseName = fileInfo.baseName()
                layer = QgsRasterLayer(path, baseName, "gdal")
                QgsProject.instance().addMapLayer(layer)
        except Exception as e:
            MsInfo(e)

    def OK_Click(self):
        self.post_grid_remove()
        self.rdo_selection()
        self.mapcanvas.refresh()
        self.scale_changed_mapcanvas()
        self.tool.scale_changed_disconnect()

    # scale에 따라 Marker 크기 변화 --  Canvastool class 별개 함수
    def scale_changed_mapcanvas(self):
        try:
            # connect 중복 연결 방지
            self.mapcanvas.scaleChanged.disconnect(self.scale_change_vertexMarker)
        except TypeError:
            pass
        self.mapcanvas.scaleChanged.connect(self.scale_change_vertexMarker)

    def scale_change_vertexMarker(self):
        self.post_grid_remove()
        try:
            if (
                self.tool.Cell_X_Center is not None
                or self.tool.Cell_Y_Center is not None
            ):
                self.draw_grid(self.tool.Cell_X_Center, self.tool.Cell_Y_Center)
        except AttributeError:
            pass

    # ================== 2017/11/6 조
    def post_grid_remove(self):
        for v in self.mapcanvas.scene().items():
            if issubclass(type(v), QgsVertexMarker):
                self.mapcanvas.scene().removeItem(v)

    def rdo_selection(self):
        # col, row 입력
        if self.rdo_xColyRowNo.isChecked():
            self.tool._FXCOL = int(self.txt_xColyRowNo_2.text())
            self.tool._FYROW = int(self.txt_xColyRowNo_1.text())
            self.tool._XCOL = int(self.txt_xColyRowNo_2.text())
            self.tool._YROW = int(self.txt_xColyRowNo_1.text())

            gird = self.row_cols_grid(
                self.txt_xColyRowNo_1.text(), self.txt_xColyRowNo_2.text(), None
            )
        # xy 입력
        elif self.rdo_xy.isChecked():
            self.xy_grid(self.layer, self.txt_xy1.text(), self.txt_xy2.text())
            x = self.txt_xy1.text()
            y = self.txt_xy2.text()

    def identify(self):
        # 캔버스 휠까지 처리 됨
        self.mapcanvas.setCursor(QtGui.QCursor(Qt.ArrowCursor))

        self.tool.scale_changed()
        self.mapcanvas.setMapTool(self.tool)

    def disableFunction(self):
        flag = self.rdo_xColyRowNo.isChecked()
        self.txt_xColyRowNo_1.setDisabled(not flag)
        self.txt_xColyRowNo_2.setDisabled(not flag)
        self.txt_xy1.setDisabled(flag)
        self.txt_xy2.setDisabled(flag)

    # grid 그리기
    def draw_grid(self, x, y):
        marker = QgsVertexMarker(self.mapcanvas)
        marker.setCenter(QgsPointXY(float(x), float(y)))

        marker.setColor(QColor(255, 0, 0))
        scale = self.mapcanvas.scale()
        # 사이즈 조절함. 가능한 맞게 조정함
        map_width = (
            self.mapcanvas.extent().xMaximum() - self.mapcanvas.extent().xMinimum()
        )
        size = (self._xsize / 150.0) * 100000 / map_width
        marker.setIconSize(size)
        marker.setIconType(QgsVertexMarker.ICON_BOX)
        marker.setPenWidth(1)
        return marker

    def hide_flow_direction(self):
        self.flow_direction.setOpacity(0)
        self.mapcanvas.refresh()

    # ----------------- Channel CS 탭 텍스트 박스 셋팅 -----------------------------
    def Set_ChannelCS_tab_default(self):
        CrossSectionType = self.CrossSectionType[0].upper()
        SingleCSChannelWidthType = self.SingleCSChannelWidthType[0].upper()

        if CrossSectionType == "CSSINGLE":
            self.chk_compound.setChecked(False)
        elif CrossSectionType == "CSCOMPOUND":
            self.chk_compound.setChecked(True)

        if SingleCSChannelWidthType == "CWGENERATION":
            self.rdo_generateCh.setChecked(True)
        elif SingleCSChannelWidthType == "CWEQUATION":
            self.rdo_useCh.setChecked(True)
        else:
            self.rdo_generateCh.setChecked(True)

        self.txt_c.setText(self.ChannelWidthEQc[0])
        self.txt_d.setText(self.ChannelWidthEQd[0])
        self.txt_e.setText(self.ChannelWidthEQe[0])
        self.txt_douwnstream.setText(self.ChannelWidthMostDownStream[0])
        self.txtLower_Region_Height.setText(self.LowerRegionHeight[0])
        self.txtLower_Region_Base_Width.setText(self.LowerRegionBaseWidth[0])
        self.txtUpper_Region_Base_Width.setText(self.UpperRegionBaseWidth[0])
        self.txtCompound_CSChannel_Width_Limit.setText(
            self.CompoundCSChannelWidthLimit[0]
        )
        self.txtRight_bank.setText(self.BankSideSlopeRight[0])
        self.txtLeft_bank.setText(self.BankSideSlopeLeft[0])

        self.txt_douwnstream.setDisabled(True)
        self.ChannelCS_rdo_able()

        self.chk_compound.clicked.connect(self.ChannelCS_rdo_able)

        self.rdo_useCh.clicked.connect(self.ChannelCS_rdo_able)
        self.rdo_generateCh.clicked.connect(self.ChannelCS_rdo_able)
        self.lisw_WSID.clicked.connect(self.ListView_WSID)
        self.lisw_WSID.currentItemChanged.connect(self.key_events)

        self.btn_Apply_WSID_value.clicked.connect(self.set_WSID_value_change)

    def key_events(self):
        try:
            index = self.lisw_WSID.currentRow()
            CrossSectionType = self.CrossSectionType[index].upper()
            SingleCSChannelWidthType = self.SingleCSChannelWidthType[index].upper()
            if SingleCSChannelWidthType == "CWGENERATION":
                self.rdo_generateCh.setChecked(True)
            elif SingleCSChannelWidthType == "CWEQUATION":
                self.rdo_useCh.setChecked(True)
            else:
                self.rdo_generateCh.setChecked(True)
            if CrossSectionType == "CSSINGLE":
                self.chk_compound.setChecked(False)
            elif CrossSectionType == "CSCOMPOUND":
                self.chk_compound.setChecked(True)
            else:
                self.chk_compound.setChecked(False)

            self.txt_c.setText(self.ChannelWidthEQc[index])
            self.txt_d.setText(self.ChannelWidthEQd[index])
            self.txt_e.setText(self.ChannelWidthEQe[index])
            self.txt_douwnstream.setText(self.ChannelWidthMostDownStream[index])
            self.txtLower_Region_Height.setText(self.LowerRegionHeight[index])
            self.txtLower_Region_Base_Width.setText(self.LowerRegionBaseWidth[index])
            self.txtUpper_Region_Base_Width.setText(self.UpperRegionBaseWidth[index])
            self.txtCompound_CSChannel_Width_Limit.setText(
                self.CompoundCSChannelWidthLimit[index]
            )
            self.txtRight_bank.setText(self.BankSideSlopeRight[index])
            self.txtLeft_bank.setText(self.BankSideSlopeLeft[index])

            self.txt_douwnstream.setDisabled(True)
            self.ChannelCS_rdo_able()

        except Exception as e:
            MsError(e)

    # 2020-07-09 박: WSID 별 값수정 후 적용 하기 버튼 이벤트
    def set_WSID_value_change(self):
        try:
            if self.lisw_WSID.currentItem():
                select_item = self.lisw_WSID.currentItem().text()

                # 2020-07-16 박:기능 변경
                for i in range(self._ChannelSettingsCount):
                    if str(self._StreamWSID[i]) == str(select_item):
                        self.ChannelWidthEQc[i] = self.txt_c.text()
                        self.ChannelWidthEQd[i] = self.txt_d.text()
                        self.ChannelWidthEQe[i] = self.txt_e.text()
                        self.ChannelWidthMostDownStream[i] = self.txt_douwnstream.text()
                        self.LowerRegionHeight[i] = self.txtLower_Region_Height.text()
                        self.LowerRegionBaseWidth[
                            i
                        ] = self.txtLower_Region_Base_Width.text()
                        self.UpperRegionBaseWidth[
                            i
                        ] = self.txtUpper_Region_Base_Width.text()
                        self.CompoundCSChannelWidthLimit[
                            i
                        ] = self.txtCompound_CSChannel_Width_Limit.text()
                        self.BankSideSlopeRight[i] = self.txtRight_bank.text()
                        self.BankSideSlopeLeft[i] = self.txtLeft_bank.text()

                        if self.rdo_generateCh.isChecked():
                            self.SingleCSChannelWidthType[i] = "CWGENERATION"
                        elif self.rdo_useCh.isChecked():
                            self.SingleCSChannelWidthType[i] = "CWEQUATION"

                        self.CrossSectionType[i] = "CSSingle"
                        if self.chk_compound.isChecked():
                            self.CrossSectionType[i] = "CSCOMPOUND"

                MsInfo("Channel setting was updated.")

            else:
                MsInfo("Select WSID ")
        except Exception as e:
            MsError(e)

    def ListView_WSID(self, index):
        try:
            CrossSectionType = self.CrossSectionType[index.row()].upper()
            SingleCSChannelWidthType = self.SingleCSChannelWidthType[
                index.row()
            ].upper()
            if SingleCSChannelWidthType == "CWGENERATION":
                self.rdo_generateCh.setChecked(True)
            elif SingleCSChannelWidthType == "CWEQUATION":
                self.rdo_useCh.setChecked(True)
            else:
                self.rdo_generateCh.setChecked(True)
            if CrossSectionType == "CSSINGLE":
                self.chk_compound.setChecked(False)
            elif CrossSectionType == "CSCOMPOUND":
                self.chk_compound.setChecked(True)
            else:
                self.chk_compound.setChecked(False)

            self.txt_c.setText(self.ChannelWidthEQc[index.row()])
            self.txt_d.setText(self.ChannelWidthEQd[index.row()])
            self.txt_e.setText(self.ChannelWidthEQe[index.row()])
            self.txt_douwnstream.setText(self.ChannelWidthMostDownStream[index.row()])
            self.txtLower_Region_Height.setText(self.LowerRegionHeight[index.row()])
            self.txtLower_Region_Base_Width.setText(
                self.LowerRegionBaseWidth[index.row()]
            )
            self.txtUpper_Region_Base_Width.setText(
                self.UpperRegionBaseWidth[index.row()]
            )
            self.txtCompound_CSChannel_Width_Limit.setText(
                self.CompoundCSChannelWidthLimit[index.row()]
            )
            self.txtRight_bank.setText(self.BankSideSlopeRight[index.row()])
            self.txtLeft_bank.setText(self.BankSideSlopeLeft[index.row()])

            self.txt_douwnstream.setDisabled(True)
            self.ChannelCS_rdo_able()

        except Exception as e:
            MsError(e)

    # Channel CS  --2017/09/08 조
    # 라디오 버튼 클릭 시 활성/비활성 함수
    def ChannelCS_rdo_able(self):
        # 활성 상태
        self.row = self.lisw_WSID.currentRow()

        # Use channel width equation 활성 상태인 경우
        if self.rdo_useCh.isChecked():
            # 2020-04-28 박: 라디오 이벤트로 배열값 변경 처리
            self.txt_douwnstream.setDisabled(True)
            self.txt_c.setDisabled(False)
            self.txt_d.setDisabled(False)
            self.txt_e.setDisabled(False)

        # Use channel width equation 비활성 상태인 경우
        elif self.rdo_generateCh.isChecked():
            self.txt_douwnstream.setDisabled(False)
            self.txt_c.setDisabled(True)
            self.txt_d.setDisabled(True)
            self.txt_e.setDisabled(True)

        # single cross section 라디오 버튼이 비활성 상태 일 때
        if self.chk_compound.isChecked():
            self.groupBox_6.setDisabled(False)
        else:
            self.groupBox_6.setDisabled(True)

    # ----------------- 2017-10-24_오전 박 Watershed Parmeters 탭 텍스트 박스 셋팅 -----------------------------
    def Set_Watershed_Parameter_tab_default(self):
        # Select watershed 콥보 박스 셋팅
        self.Set_Watershed_combo()

        # 함수로 빼야함 급해서 그냥 넣음
        combolist = ["Constant", "Linear", "Exponential"]
        #         combolist = ('Linear','Exponential','Constant')
        self.cmbUnsturatedType.addItems(combolist)
        self.cmbUnsturatedType.currentIndexChanged.connect(self.chage_UnsturatedType)

        for interception_method in EnumInterceptionMethod:
            self.cmbInterceptionMethodType.addItem(
                interception_method.name, interception_method.value
            )

        self.cmbInterceptionMethodType.setCurrentIndex(
            self.cmbInterceptionMethodType.findText("None")
        )

        for PET_method in EnumPETMethod:
            self.cmbPETMethodType.addItem(PET_method.name, PET_method.value)

        self.cmbPETMethodType.setCurrentIndex(self.cmbPETMethodType.findText("None"))

        for snowmelt_method in EnumSnowMeltMethod:
            self.cmbSnowmeltMethodType.addItem(
                snowmelt_method.name, snowmelt_method.value
            )

        self.cmbSnowmeltMethodType.setCurrentIndex(
            self.cmbSnowmeltMethodType.findText("None")
        )

        ## 최하류 셀값 설정정
        self.Set_MostDownStream()
        self.cb_selectws.currentIndexChanged.connect(self.SelectWsCombobox)

        # 2020-05-19 박:콤보 박스 셋팅후 각각의 상류 하류 유역 정보가 설정 되지 않아서 호출
        self.SelectWsCombobox()

        self.btnApplyWS.clicked.connect(self.UserSet_Add)
        self.btnRemoveWS.clicked.connect(self.UserSet_remove)
        self.SetWatershedstream()
        # 2020-05-19 박:콤보 박스 셋팅후 각각의 상류 하류 유역 정보가 설정 되지 않아서 호출
        self.SelectWsCombobox()

        # 콤보 박스에 유역 설정 하기

    def Set_Watershed_combo(self):
        WS_list = []
        wscount = self._wsinfo.WScount
        AllItem = self._wsinfo.WSIDsAll
        for i in range(wscount):
            WS_list.append(str(AllItem[i]))
        WS_list.sort()

        self.cb_selectws.clear()
        self.cb_selectws.addItems(WS_list)

    def Set_MostDownStream(self):
        if self._SubWatershedCount == 0:
            templist = []
            if len(self._StreamWSID) > 0:
                for id in range(len(self._StreamWSID)):
                    if str(self._StreamWSID[id]) not in templist:
                        self.SetMostDownStream(self._StreamWSID[id])
                        templist.append(str(self._StreamWSID[id]))

    def chage_UnsturatedType(self):
        self.selectText = self.cmbUnsturatedType.currentText()

        value = "0.1"
        if self.selectText == "Linear":
            value = "0.2"
        elif self.selectText == "Exponential":
            value = "6.4"

        self.txtCoefUnsatruatedk.setText(value)
        self.txtCoefUnsatruatedk.setEnabled(True)

    # 콤보박스 선택시 하류 유역과 상류 유역의 콤보박스에 값 셋팅
    def SelectWsCombobox(self):
        self.project_use_flag = False
        # 2018-01-29 박: Watershed parmeter 함수 호출
        # 하류 유역 정보 셋팅
        selectWS = self.cb_selectws.currentText()
        DownSW = []
        Dllresult_Down = self._wsinfo.downStreamWSIDs(int(selectWS))
        Dllresult_Down_count = self._wsinfo.downStreamWSCount(int(selectWS))

        for i in range(Dllresult_Down_count):
            DownSW.append(Dllresult_Down[i])

        if len(DownSW) > 0:
            self.lisw_DownWS.clear()
            for i in range(len(DownSW)):
                if DownSW[i] > 0:
                    item = QListWidgetItem(str(DownSW[i]))
                    self.lisw_DownWS.addItem(item)
        else:
            self.lisw_DownWS.clear()

        # 상류 유역 정보 셋팅
        UPSW = []
        Dllresult_UP = self._wsinfo.upStreamWSIDs(int(selectWS))
        Dllresult_UP_count = self._wsinfo.upStreamWSCount(int(selectWS))
        for i in range(Dllresult_UP_count):
            UPSW.append(Dllresult_UP[i])

        # UPSW.extend(Dllresult_UP)
        if len(UPSW) > 0:
            self.lisw_UpWS.clear()
            for s in range(len(UPSW)):
                if UPSW[s] > 0:
                    item1 = QListWidgetItem(str(UPSW[s]))
                    self.lisw_UpWS.addItem(item1)
        else:
            self.lisw_UpWS.clear()

        try:
            # global self._wsinfo
            # 콤보박스에서 받은 내용을 텍스트 박스에 넣는 방법
            sws_dict = self._wsinfo.subwatershedPars(int(selectWS))

            iniSaturation = str(ex_to_float(sws_dict.iniSaturation))
            minSlopeOF = str(ex_to_float(sws_dict.minSlopeOF))
            minSlopeChBed = str(ex_to_float(sws_dict.minSlopeChBed))

            # 2018-03-12 박: 화면 수정
            UKType = int(sws_dict.unSatKType)
            coefUK = str(ex_to_float(sws_dict.coefUnsaturatedK))
            interceptMethodType = int(sws_dict.interceptMethod)
            potentialETMethodType = int(sws_dict.potentialETMethod)
            snowMeltMethodType = int(sws_dict.snowMeltMethod)

            minChBaseWidth = str(ex_to_float(sws_dict.minChBaseWidth))
            chRoughness = str(ex_to_float(sws_dict.chRoughness))
            dryStreamOrder = str(sws_dict.dryStreamOrder)
            ccLCRoughness = str(ex_to_float(sws_dict.ccLCRoughness))
            ccSoilDepth = str(ex_to_float(sws_dict.ccSoilDepth))
            ccPorosity = str(ex_to_float(sws_dict.ccPorosity))
            ccWFSuctionHead = str(ex_to_float(sws_dict.ccWFSuctionHead))
            ccHydraulicK = str(ex_to_float(sws_dict.ccHydraulicK))
            iniFlow = str(ex_to_float(sws_dict.iniFlow))
            if iniFlow.upper() == "NONE":
                iniFlow = "0"
            etCoeff = str(ex_to_float(sws_dict.etCoeff))
            TempSnowRain = str(ex_to_float(sws_dict.tempSnowRain))
            smeltingTemp = str(ex_to_float(sws_dict.smeltingTemp))
            snowCovRatio = str(ex_to_float(sws_dict.snowCovRatio))
            smeltCoef = str(ex_to_float(sws_dict.smeltCoef))

            self.txtIniSaturation.setText(iniSaturation)
            self.txtMinSlopeOF.setText(minSlopeOF)
            self.txtMinSlopeChBed.setText(minSlopeChBed)
            self.txtMinChBaseWidth.setText(str(minChBaseWidth))
            self.txtIniFlow.setText(str(iniFlow))
            self.txtChRoughness.setText(chRoughness)
            self.txtDryStreamOrder.setText(dryStreamOrder)
            self.txtCalCoefLCRoughness.setText(ccLCRoughness)
            self.txtCalCoefSoilDepth.setText(ccSoilDepth)
            self.txtCalCoefPorosity.setText(ccPorosity)
            self.txtCalCoefWFSuctionHead.setText(ccWFSuctionHead)
            self.txtCalCoefHydraulicK.setText(ccHydraulicK)
            self.txtETCoef.setText(etCoeff)
            self.txtTempSnowRain.setText(TempSnowRain)
            self.txtSnowmeltingTemp.setText(smeltingTemp)
            self.txtSnowCovRatio.setText(snowCovRatio)
            self.txtSnowmeltCoef.setText(smeltCoef)

            self.txtCoefUnsatruatedk.setDisabled(bool(UKType < 0 or UKType > 2))
            UKType = UKType if 0 <= UKType and UKType < 3 else 1
            self.cmbUnsturatedType.setCurrentIndex(UKType)
            interceptMethod_index = self.cmbInterceptionMethodType.findData(
                interceptMethodType
            )
            self.cmbInterceptionMethodType.setCurrentIndex(interceptMethod_index)
            potentialETMethodType_index = self.cmbPETMethodType.findData(
                potentialETMethodType
            )
            self.cmbPETMethodType.setCurrentIndex(potentialETMethodType_index)
            snowMeltMethodType_index = self.cmbSnowmeltMethodType.findData(
                snowMeltMethodType
            )
            self.cmbSnowmeltMethodType.setCurrentIndex(snowMeltMethodType_index)

            self.txtCoefUnsatruatedk.setText(coefUK)

        # 예외가 발생했을때 예외 값을 셋팅
        except Exception as e:
            self.txtIniSaturation.setText("0.9")
            self.txtMinSlopeOF.setText("0.0001")
            self.txtMinSlopeChBed.setText("0.0001")

            intAll = float(self.GridCellSize)
            if intAll > 0:
                cal_MinChBaseWidth = intAll / 10
            self.txtMinChBaseWidth.setText(str(cal_MinChBaseWidth))
            self.txtIniFlow.setText("0")

            self.cmbUnsturatedType.setCurrentIndex(0)
            self.txtCoefUnsatruatedk.setText("0.2")

            self.txtChRoughness.setText("0.045")
            self.txtDryStreamOrder.setText("0")
            self.txtCalCoefLCRoughness.setText("1")
            self.txtCalCoefSoilDepth.setText("1")
            self.txtCalCoefPorosity.setText("1")
            self.txtCalCoefWFSuctionHead.setText("1")
            self.txtCalCoefHydraulicK.setText("1")
            InterceptionMethod_None_index = self.cmbInterceptionMethodType.findData(10)
            self.cmbInterceptionMethodType.setCurrentIndex(
                InterceptionMethod_None_index
            )
            PETMethod_None_index = self.cmbPETMethodType.findData(10)
            self.cmbPETMethodType.setCurrentIndex(PETMethod_None_index)
            self.txtETCoef.setText("1")
            SnowmeltMethod_None_index = self.cmbSnowmeltMethodType.findData(10)
            self.cmbSnowmeltMethodType.setCurrentIndex(SnowmeltMethod_None_index)
            self.txtTempSnowRain.setText("1")
            self.txtSnowmeltingTemp.setText("1")
            self.txtSnowCovRatio.setText("1")
            self.txtSnowmeltCoef.setText("1")
            item1 = QListWidgetItem(str(self._StreamWSID))
            self.lisw_UserSet.addItem(item1)

    def UserSet_Add(self):
        id = int(self.cb_selectws.currentText())
        items = self.lisw_UserSet.findItems(str(id), Qt.MatchExactly)
        if len(items) == 0:
            item1 = QListWidgetItem(str(id))
            self.lisw_UserSet.addItem(item1)

        IniSaturation = self.txtIniSaturation.text()
        MinSlopeOF = self.txtMinSlopeOF.text()
        MinSlopeChBed = self.txtMinSlopeChBed.text()
        IniFlow = self.txtIniFlow.text()

        UnsaturatedKType_int = self.cmbUnsturatedType.currentIndex()

        MinChBaseWidth = self.txtMinChBaseWidth.text()
        CoefUnsatruatedk = self.txtCoefUnsatruatedk.text()
        ChRoughness = self.txtChRoughness.text()
        DryStreamOrder = self.txtDryStreamOrder.text()
        CalCoefLCRoughness = self.txtCalCoefLCRoughness.text()
        CalCoefSoilDepth = self.txtCalCoefSoilDepth.text()
        CalCoefPorosity = self.txtCalCoefPorosity.text()
        CalCoefWFSuctionHead = self.txtCalCoefWFSuctionHead.text()
        CalCoefHydraulicK = self.txtCalCoefHydraulicK.text()

        if self.chkInterception.isChecked():
            interceptMethod = self.cmbInterceptionMethodType.currentData()
        else:
            interceptMethod = self.cmbInterceptionMethodType.itemData(
                self.cmbInterceptionMethodType.findText("None")
            )

        if self.chkEvapotranspiration.isChecked():
            potentialETMethod = self.cmbPETMethodType.currentData()
            etCoeff = self.txtETCoef.text()
        else:
            potentialETMethod = self.cmbPETMethodType.itemData(
                self.cmbPETMethodType.findText("None")
            )
            etCoeff = "0"

        if self.chkSnowMelt.isChecked():
            snowMeltMethod = self.cmbSnowmeltMethodType.currentData()
            tempSnowRain = self.txtTempSnowRain.text()
            smeltingTemp = self.txtSnowmeltingTemp.text()
            snowCovRatio = self.txtSnowCovRatio.text()
            smeltCoef = self.txtSnowmeltCoef.text()
        else:
            snowMeltMethod = self.cmbSnowmeltMethodType.itemData(
                self.cmbSnowmeltMethodType.findText("None")
            )
            tempSnowRain = "0"
            smeltingTemp = "0"
            snowCovRatio = "0"
            smeltCoef = "0"

        try:
            self._wsinfo.setOneSWSParsAndUpdateAllSWSUsingNetwork(
                id,
                float(IniSaturation),
                float(MinSlopeOF),
                int(UnsaturatedKType_int),
                float(CoefUnsatruatedk),
                float(MinSlopeChBed),
                float(MinChBaseWidth),
                float(ChRoughness),
                int(DryStreamOrder),
                float(CalCoefLCRoughness),
                float(CalCoefPorosity),
                float(CalCoefWFSuctionHead),
                float(CalCoefHydraulicK),
                float(CalCoefSoilDepth),
                int(interceptMethod),
                int(potentialETMethod),
                float(etCoeff),
                int(snowMeltMethod),
                float(tempSnowRain),
                float(smeltingTemp),
                float(snowCovRatio),
                float(smeltCoef),
                float(IniFlow),
            )
            MsInfo("Apply parameter was completed")
        except Exception as e:
            MsError(f"Apply parameter was not completed! {e}")

    # 사용자 정의 제거 함수
    def UserSet_remove(self):
        id = self.cb_selectws.currentText()
        comboindex = self.cb_selectws.currentIndex()

        if id in self._StreamWSID:
            MsError("Most downstream watershed parameters can not be removed.")

        else:
            result = self._wsinfo.removeUserParametersSetting(int(id))
            items = self.lisw_UserSet.findItems(id, Qt.MatchFixedString)

            if result and items:
                index = self.lisw_UserSet.row(items[0])
                self.lisw_UserSet.takeItem(index)
                MsInfo("Remove parameter was completed")

                # 변경된 값을 다시 표출하기.
                self.SelectWsCombobox()

    def SetWatershedstream(self):
        self.ID = []
        self.IniSaturation = []
        self.MinSlopeOF = []
        self.MinSlopeChBed = []
        self.MinChBaseWidth = []
        self.ChRoughness = []
        self.DryStreamOrder = []
        self.IniFlow = []
        self.CalCoefLCRoughness = []
        self.CalCoefPorosity = []
        self.CalCoefWFSuctionHead = []
        self.CalCoefHydraulicK = []
        self.CalCoefSoilDepth = []
        self.UserSet = []
        self.UnsaturatedKType = []
        self.CoefUnsaturatedK = []
        InterceptionMethod = []
        PETMethod = []
        ETCoef = []
        SnowmeltMethod = []
        TempSnowRain = []
        SnowmeltingTemp = []
        SnowCovRatio = []
        SnowmeltCoef = []
        doc = ET.parse(self.ProjectFile)
        root = doc.getroot()
        # 최하류 유역 Id 값
        try:
            if self._SubWatershedCount == 0:
                intAll = float(self.GridCellSize)
                cal_MinChBaseWidth = 0

                if intAll > 0:
                    cal_MinChBaseWidth = intAll / 10

                for id in self._StreamWSID:
                    self._wsinfo.setOneSWSParsAndUpdateAllSWSUsingNetwork(
                        int(id),
                        0.9,
                        0.0001,
                        1,
                        0.2,
                        0.0001,
                        float(cal_MinChBaseWidth),
                        0.045,
                        0,
                        1,
                        1,
                        1,
                        1,
                        1,
                        1,
                        2,
                        1,
                        1,
                        0,
                        1,
                        1,
                        1,
                        0,
                    )

                    item1 = QListWidgetItem(str(id))
                    self.lisw_UserSet.addItem(item1)

                return

            xmltoDict = self._xmltodict["GRMProject"]["SubWatershedSettings"]
            if self._SubWatershedCount == 1:
                xmltoDict = [xmltoDict]

            for i, watershed in enumerate(xmltoDict):
                self.ID.append(str(watershed["ID"]))
                self.IniSaturation.append(watershed["IniSaturation"])
                self.MinSlopeOF.append(watershed["MinSlopeOF"])
                self.MinSlopeChBed.append(watershed["MinSlopeChBed"])
                self.MinChBaseWidth.append(watershed["MinChBaseWidth"])
                self.ChRoughness.append(watershed["ChRoughness"])
                self.DryStreamOrder.append(watershed["DryStreamOrder"])
                self.IniFlow.append(watershed["IniFlow"])

                self.CoefUnsaturatedK.append(watershed["CoefUnsaturatedK"])
                self.CalCoefLCRoughness.append(watershed["CalCoefLCRoughness"])
                self.CalCoefPorosity.append(watershed["CalCoefPorosity"])
                self.CalCoefWFSuctionHead.append(watershed["CalCoefWFSuctionHead"])
                self.CalCoefHydraulicK.append(watershed["CalCoefHydraulicK"])
                self.CalCoefSoilDepth.append(watershed["CalCoefSoilDepth"])
                InterceptionMethod.append(watershed["InterceptionMethod"])
                PETMethod.append(watershed["PETMethod"])
                ETCoef.append(watershed["ETCoef"])
                SnowmeltMethod.append(watershed["SnowmeltMethod"])
                TempSnowRain.append(watershed["TempSnowRain"])
                SnowmeltingTemp.append(watershed["SnowmeltingTemp"])
                SnowCovRatio.append(watershed["SnowCovRatio"])
                SnowmeltCoef.append(watershed["SnowmeltCoef"])
                usersetString = watershed["UserSet"]
                self.UserSet.append(usersetString)

                self.UnsaturatedKType.append(watershed["UnsaturatedKType"])
                UnsaturatedKType_int = 0
                # 2020-05-19 박: 기능 추가
                UnsaturatedKType = self.UnsaturatedKType[i]
                if UnsaturatedKType == "Constant":
                    UnsaturatedKType_int = 0
                elif UnsaturatedKType == "Linear":
                    UnsaturatedKType_int = 1
                elif UnsaturatedKType == "Exponential":
                    UnsaturatedKType_int = 2

                # 2022.02.09 동 : Userset은 UI에서 사용자가 값을 변경하거나, mostdownstream 값일 경우에 True 값이 적용됨.
                # Open project시, gmp 파일에 있는 값을 그대로 UI에 출력해야 하나, False인 값들은 dll에서 받아오는 값과 동일해야 정상.
                # 아니라면 데이터 파일을 의심하거나, gmp 파일의 오류를 의심해야함.
                if (
                    usersetString.upper() == "TRUE"
                    or str(self.ID[i]) in self._StreamWSID
                ):
                    self._wsinfo.setOneSWSParsAndUpdateAllSWSUsingNetwork(
                        int(self.ID[i]),
                        float(self.IniSaturation[i]),
                        float(self.MinSlopeOF[i]),
                        int(UnsaturatedKType_int),
                        float(self.CoefUnsaturatedK[i]),
                        float(self.MinSlopeChBed[i]),
                        float(self.MinChBaseWidth[i]),
                        float(self.ChRoughness[i]),
                        int(self.DryStreamOrder[i]),
                        float(self.CalCoefLCRoughness[i]),
                        float(self.CalCoefPorosity[i]),
                        float(self.CalCoefWFSuctionHead[i]),
                        float(self.CalCoefHydraulicK[i]),
                        float(self.CalCoefSoilDepth[i]),
                        int(EnumInterceptionMethod[InterceptionMethod[i]].value),
                        int(EnumPETMethod[PETMethod[i]].value),
                        float(ETCoef[i]),
                        int(EnumSnowMeltMethod[SnowmeltMethod[i]].value),
                        float(TempSnowRain[i]),
                        float(SnowmeltingTemp[i]),
                        float(SnowCovRatio[i]),
                        float(SnowmeltCoef[i]),
                        float(self.IniFlow[i]),
                    )

                    item1 = QListWidgetItem(str(self.ID[i]))
                    self.lisw_UserSet.addItem(item1)

        except Exception as esd:
            MsError(esd)

    def SetMostDownStream_combobox(self):
        count = self.cb_selectws.count()
        for i in range(0, count):
            selectWS = self.cb_selectws.itemText(i)

            # 2018-07-24 박: 기존 소스
            # 목록중에 최하류 셀값 자동으로 선택하게 하는 기능
            # 그래서 리스트 목록중에 0번째 있는 목록을 자동으로 선택하게 하였음
            if str(selectWS) == str(self._StreamWSID[0]):
                self.cb_selectws.setCurrentIndex(i)
                return

    # ============================ Flow Control 탭 시작 ===============================================
    def Set_FlowControl_tab_default(self):
        try:
            # 테이블 셀값을 변경 불가능 하게 설정
            self.tlbFlowControl.setEditTriggers(QAbstractItemView.NoEditTriggers)
            # 테이블에 초기 셋팅
            self.FlowControlTableSetting()
            # 테이블에 값 셋팅후 화면에 점 표시
            self.FlowContorGird_paint()
            self.btnFlowControl_AddCell.clicked.connect(self.FlowControlAddCell)
            self.btnFWCEdit.clicked.connect(self.FlowControlEdit)
            self.tlbFlowControl.itemClicked.connect(self.tlbFlowControl_clik_enent)
            self.btnFlowRemove.clicked.connect(self.RemoveTalbeRow)
            #             self.btnfcgotogrid.clicked.connect(self.btnFCGotoGrid)
            self.btnfcgotogrid.clicked.connect(
                lambda: self.btnGotoGrid(self.tlbFlowControl)
            )

        except Exception as e:
            MsError(e)

    # Flow control 테이블 셋팅
    # 프로젝트 파일에서 데이터 값이 있으면 테이블에 값을 셋팅
    def FlowControlTableSetting(self):
        try:
            self.tlbFlowControl.setColumnCount(len(self.flowEle))
            self.tlbFlowControl.setHorizontalHeaderLabels(self.flowEle)
            self.tlbFlowControl.verticalHeader().hide()
            pro_file = self._xmltodict["GRMProject"]["ProjectSettings"]["ProjectFile"]

            if self._Flowcontrolgrid_flag == False:
                self._FlowControlCount = self._FlowControlCount

            if self._FlowControlCount < 1:
                return

            flowGrid = self._xmltodict["GRMProject"]["FlowControlGrid"]
            if self._FlowControlCount == 1:
                flowGrid = [flowGrid]

            for i, flowItem in enumerate(flowGrid):
                self.tlbFlowControl.insertRow(i)
                for j, t in enumerate(self.flowEle):
                    s = ""
                    if (t in flowItem) and (
                        flowItem[t] != "ReservoirOperation" or j != 5
                    ):
                        s = flowItem[t]
                    self.tlbFlowControl.setItem(i, j, QTableWidgetItem(s))

        except Exception as e:
            MsError(e)

    # 사용자 추가 입력창 화면
    def FlowControlAddCell(self):
        if self.tool._FXCOL == 0 and self.tool._FYROW == 0:
            self._FXCOL = 0
            self._FYROW = 0
            MsInfo(" No cells selected. ")
        else:
            self._FXCOL = self.tool._FXCOL
            self._FYROW = self.tool._FYROW
            self._AddFlowcontrol_Edit_or_Insert_type = "Insert"
            results = AddFlowControl(
                self.ProjectFile,
                self._AddFlowcontrol_Edit_or_Insert_type,
                _DataTimeFormat=self.dataTimeFormat,
            )
            results.exec_()

            self._AddFlowcontrolFilePath = results._AddFlowcontrolFilePath
            self._AddFlowcontrolType = results._AddFlowcontrolType
            self._AddFlowcontrolTimeInterval = results._AddFlowcontrolTimeInterval
            self._AddFlowcontrolName = results._AddFlowcontrolName
            self._AddFlowcontrol_Edit_or_Insert_type = (
                results._AddFlowcontrol_Edit_or_Insert_type
            )
            self._AddFlowcontrol_IniStorage = results._AddFlowcontrol_IniStorage
            self._AddFlowcontrol_MaxStorage = results._AddFlowcontrol_MaxStorage
            self._AddNomalHighStorage = results._AddNomalHighStorage
            self._AddRestrictedStorage = results._AddRestrictedStorage
            self._AddRetiPeriodSt = results._AddRetiPeriodSt
            self._AddRetiPeriodEd = results._AddRetiPeriodEd
            self._AddFlowcontrol_ROType = results._AddFlowcontrol_ROType
            self._AddFlowcontrol_AutoROMmaxOutflow_CMS = (
                results._AddFlowcontrol_AutoROMmaxOutflow_CMS
            )
            self._AddFlowcontrol_ROConstQ = results._AddFlowcontrol_ROConstQ
            self._AddFlowcontrol_ROConstQDuration = (
                results._AddFlowcontrol_ROConstQDuration
            )
            self._EditFlowFlowDataFile = results._EditFlowFlowDataFile

            if self._Flowcontrolgrid_flag:
                if self._AddFlowcontrol_Edit_or_Insert_type == "Insert":
                    self.ADDFlowData()
                    self._Flowcontrolgrid_flag_Insert = False

    def ADDFlowData(self):
        try:
            counts = self.tlbFlowControl.rowCount()
            if self._FXCOL != 0 and self._FYROW != 0:
                self.tlbFlowControl.insertRow(counts)
                self.tlbFlowControl.setItem(
                    counts, 0, QTableWidgetItem(self._AddFlowcontrolName)
                )
                self.tlbFlowControl.setItem(
                    counts, 1, QTableWidgetItem(str(self._FYROW))
                )
                self.tlbFlowControl.setItem(
                    counts, 2, QTableWidgetItem(str(self._FXCOL))
                )

                self._FXCOL = 0
                self._FYROW = 0
                self.tlbFlowControl.setItem(
                    counts, 3, QTableWidgetItem(self._AddFlowcontrolTimeInterval)
                )
                self.tlbFlowControl.setItem(
                    counts, 4, QTableWidgetItem(self._AddFlowcontrolType)
                )
                self.tlbFlowControl.setItem(
                    counts, 5, QTableWidgetItem(self._AddFlowcontrolFilePath)
                )
                self.tlbFlowControl.setItem(
                    counts, 6, QTableWidgetItem(self._AddFlowcontrol_IniStorage)
                )
                self.tlbFlowControl.setItem(
                    counts, 7, QTableWidgetItem(self._AddFlowcontrol_MaxStorage)
                )
                self.tlbFlowControl.setItem(
                    counts, 8, QTableWidgetItem(self._AddNomalHighStorage)
                )
                self.tlbFlowControl.setItem(
                    counts, 9, QTableWidgetItem(self._AddRestrictedStorage)
                )
                self.tlbFlowControl.setItem(
                    counts, 10, QTableWidgetItem(self._AddRetiPeriodSt)
                )
                self.tlbFlowControl.setItem(
                    counts, 11, QTableWidgetItem(self._AddRetiPeriodEd)
                )
                self.tlbFlowControl.setItem(
                    counts, 12, QTableWidgetItem(self._AddFlowcontrol_ROType)
                )
                self.tlbFlowControl.setItem(
                    counts,
                    13,
                    QTableWidgetItem(self._AddFlowcontrol_AutoROMmaxOutflow_CMS),
                )
                self.tlbFlowControl.setItem(
                    counts, 14, QTableWidgetItem(self._AddFlowcontrol_ROConstQ)
                )
                self.tlbFlowControl.setItem(
                    counts, 15, QTableWidgetItem(self._AddFlowcontrol_ROConstQDuration)
                )

            self._Flowcontrolgrid_flag = True
            self.UpdateFlowControl()

            # 테이블에 값 셋팅후 화면에 점 표시
            if self.chkFlowContorGird.isChecked():
                self.FlowContorGird_paint()
        except Exception as e:
            MsError(e)

    def FlowControlEdit(self):
        self._FlowControlTable = self.tlbFlowControl
        row = self.tlbFlowControl.currentRow()
        self._EditFlowCurrentRow = row
        if row > -1:
            self._EditFlowName = self.tlbFlowControl.item(row, 0).text()
            self._EditFlowColX = self.tlbFlowControl.item(row, 1).text()
            self._EditFlowRowY = self.tlbFlowControl.item(row, 2).text()
            self._EditFlowDT = self.tlbFlowControl.item(row, 3).text()
            self._EditFlowControlType = self.tlbFlowControl.item(row, 4).text()
            self._EditFlowFlowDataFile = self.tlbFlowControl.item(row, 5).text()
            self._EditFlowIniStorage = self.tlbFlowControl.item(row, 6).text()
            self._EditFlowMaxStorage = self.tlbFlowControl.item(row, 7).text()
            self._EditNomalHighStorage = self.tlbFlowControl.item(row, 8).text()
            self._EditRestrictedStorage = self.tlbFlowControl.item(row, 9).text()
            self._EditRetiPeriodSt = self.tlbFlowControl.item(row, 10).text()
            self._EditRetiPeriodEd = self.tlbFlowControl.item(row, 11).text()
            self._EditFlowROType = self.tlbFlowControl.item(row, 12).text()
            self._EditFlowAutoROMmaxOutflow_CMS = self.tlbFlowControl.item(
                row, 13
            ).text()
            self._EditFlowROConstQ = self.tlbFlowControl.item(row, 14).text()
            self._EditFlowROConstQDuration = self.tlbFlowControl.item(row, 15).text()

            self.flowEle
            self._AddFlowcontrol_Edit_or_Insert_type = "Edit"
            self._FlowControlCount = self._FlowControlCount
            results = AddFlowControl(
                self.ProjectFile,
                self._AddFlowcontrol_Edit_or_Insert_type,
                self._EditFlowName,
                self._EditFlowDT,
                self._EditFlowControlType,
                self._EditFlowFlowDataFile,
                self._EditFlowIniStorage,
                self._EditFlowMaxStorage,
                self._EditNomalHighStorage,
                self._EditRestrictedStorage,
                self._EditRetiPeriodSt,
                self._EditRetiPeriodEd,
                self._EditFlowROType,
                self._EditFlowAutoROMmaxOutflow_CMS,
                self._EditFlowROConstQ,
                self._EditFlowROConstQDuration,
                self.dataTimeFormat,
            )
            results.exec_()

            self._FlowControlTable.setItem(
                row, 0, QTableWidgetItem(results._EditFlowName)
            )
            self._FlowControlTable.setItem(
                row, 3, QTableWidgetItem(results._EditFlowDT)
            )
            self._FlowControlTable.setItem(
                row, 4, QTableWidgetItem(results._EditFlowControlType)
            )
            self._FlowControlTable.setItem(
                row, 5, QTableWidgetItem(results._EditFlowFlowDataFile)
            )
            self._FlowControlTable.setItem(
                row, 6, QTableWidgetItem(results._EditFlowIniStorage)
            )
            self._FlowControlTable.setItem(
                row, 7, QTableWidgetItem(results._EditFlowMaxStorage)
            )
            self._FlowControlTable.setItem(
                row, 8, QTableWidgetItem(results._EditNomalHighStorage)
            )
            self._FlowControlTable.setItem(
                row, 9, QTableWidgetItem(results._EditRestrictedStorage)
            )
            self._FlowControlTable.setItem(
                row, 10, QTableWidgetItem(results._EditRetiPeriodSt)
            )
            self._FlowControlTable.setItem(
                row, 11, QTableWidgetItem(results._EditRetiPeriodEd)
            )
            self._FlowControlTable.setItem(
                row, 12, QTableWidgetItem(results._EditFlowROType)
            )
            self._FlowControlTable.setItem(
                row, 13, QTableWidgetItem(results._EditFlowAutoROMmaxOutflow_CMS)
            )
            self._FlowControlTable.setItem(
                row, 14, QTableWidgetItem(results._EditFlowROConstQ)
            )
            self._FlowControlTable.setItem(
                row, 15, QTableWidgetItem(results._EditFlowROConstQDuration)
            )

            self.UpdateFlowControl()

        else:
            MsInfo("Check! select row ")

    def UpdateFlowControl(self):
        # 딕셔너리 삭제
        if self._FlowControlCount > 0:
            del self._xmltodict["GRMProject"]["FlowControlGrid"]
        DictoXml = unparse(self._xmltodict)

        ET.register_namespace("", "http://tempuri.org/GRMProject.xsd")
        xmltree = ET.ElementTree(ET.fromstring(DictoXml))
        root = xmltree.getroot()
        count = self.tlbFlowControl.rowCount()
        self._FlowControlCount = count

        for row in range(0, self._FlowControlCount):
            child = ET.Element("FlowControlGrid")
            root.append(child)

            for i in range(len(self.flowEle)):
                element = ET.Element(self.flowEle[i])
                item = self.tlbFlowControl.item(row, i)
                element.text = item.text() if item else ""
                child.append(element)

        xmltree_string = ET.tostring(xmltree.getroot())
        docs = dict(parse(xmltree_string))
        self._xmltodict.clear()
        self._xmltodict.update(docs)

    def tlbFlowControl_clik_enent(self):
        global _ClickX, _ClickY
        row = self.tlbFlowControl.currentRow()
        _ClickX = self.tlbFlowControl.item(row, 1).text()
        _ClickY = self.tlbFlowControl.item(row, 2).text()

    def RemoveTalbeRow(self):
        row = self.tlbFlowControl.currentIndex().row()
        # 선택된 Row 가 있을때
        if row > -1:
            mess = "Are you sure you want to delete the selected items?"
            result = QMessageBox.question(
                None, "Flow Control Grid", mess, QMessageBox.Yes, QMessageBox.No
            )
            if result == QMessageBox.Yes:
                # 사용자가 한번이라도 수정한 사항이 있으면 플래그값 True 로 변경하여 사용자 수정
                _Flowcontrolgrid_flag = True
                self.tlbFlowControl.removeRow(row)

                self.UpdateFlowControl()
                # 테이블에 값 셋팅후 화면에 점 표시

                self.post_grid_remove2()
                self.FlowContorGird_paint()
                if self.chkWatch_Point.isChecked():
                    self.watchpoint_paint()

    # 2. xy좌표로
    def xy_grid(self, layer, xcoord, ycoord):
        try:
            xc = float(xcoord)
            yc = float(ycoord)
            row = int(((self._ymax - yc) / self._ysize))
            column = int(((xc - self._xmin) / self._xsize))
            self.lblColRow.setText("xCol, yRow:" + str(column) + " , " + str(row))
            if row < 0 or column < 0 or self._height <= column or self._width <= row:
                row = "out of extent"
                column = "out of extent"
                MsInfo("{0}, {1}".format(str(column), str(row)))
            else:
                self.tool.Cell_X_Center = (
                    self._xmin + self._xsize / 2 + self._xsize * (column)
                )
                self.tool.Cell_Y_Center = (
                    self._ymax - self._ysize / 2 - self._ysize * (row)
                )  # (extent.yMinimum())
                if (
                    self.tool.Cell_X_Center <= self._xmax
                    or self._xmin <= self.tool.Cell_X_Center
                    or self.tool.Cell_Y_Center <= self._ymax
                    or self._ymin <= self.tool.Cell_Y_Center
                ):
                    self.draw_grid(self.tool.Cell_X_Center, self.tool.Cell_Y_Center)
        except Exception as e:
            MsError(e)


class CanvasTool(QgsMapTool):
    def __init__(self, canvas):
        QgsMapTool.__init__(self, canvas)
        self.canvas = canvas
        self.layer = self.canvas.layers()[0]
        self._wsinfo = _get_set_control.get_wsinfo()
        self._GreenAmptCount = _get_set_control.get_GreenAmptCount()
        self._xmltodict = _get_set_control.get_xmltodict()
        self._SoilDepthCount = _get_set_control.get_SoilDepthCount()
        self._LandCoverCount = _get_set_control.get_LandCoverCount()
        self._FYROW = 0
        self._YROW = 0
        self._FXCOL = 0
        self._XCOL = 0

        self._width = self.layer.width()
        self._height = self.layer.height()
        self._xsize = self.layer.rasterUnitsPerPixelX()
        self._ysize = self.layer.rasterUnitsPerPixelY()
        self._extent = self.layer.extent()
        self._ymax = self._extent.yMaximum()
        self._ymin = self._extent.yMinimum()
        self._xmax = self._extent.xMaximum()
        self._xmin = self._extent.xMinimum()
        self.Cell_X_Center = 0
        self.Cell_Y_Center = 0

    def scale_changed(self):
        self.canvas.scaleChanged.connect(self.scale_change_marker)

    def scale_changed_disconnect(self):
        try:
            self.canvas.scaleChanged.disconnect(self.scale_change_marker)
        except:
            pass

    # canvas scale이 변화할 때  marker를 새로 그림
    def scale_change_marker(self):
        if self.Cell_X_Center != 0 and self.Cell_Y_Center != 0:
            self.post_vertex_remove()
            self.create_vertex(self.Cell_X_Center, self.Cell_Y_Center)

    # 이전에 생성한 vertexMaker제거 함
    def post_vertex_remove(self):
        for v in self.canvas.scene().items():
            if issubclass(type(v), QgsVertexMarker):
                self.canvas.scene().removeItem(v)

    def create_vertex(self, x, y):
        marker = QgsVertexMarker(self.canvas)
        marker.setCenter(QgsPointXY(x, y))
        marker.setColor(QColor(255, 0, 0))
        width_Map = self.canvas.extent().xMaximum() - self.canvas.extent().xMinimum()
        Size_Marker = (self._xsize / 150.0) * 100000 / width_Map
        marker.setIconSize(Size_Marker)
        marker.setIconType(QgsVertexMarker.ICON_BOX)
        marker.setPenWidth(1)

    def getCVID(self, Rt, Ct):
        cvid_v = 0
        for c in range(self._width):
            for r in range(Ct):
                xxx = c * self._xsize + self._xmin
                yyy = self._ymax - r * self._ysize
                ident = self.layer.dataProvider().identify(
                    QgsPointXY(xxx, yyy), QgsRaster.IdentifyFormatValue
                )

                # 2020-01-28 박: 변경은 했으나 맞는지 확인이 안됨
                if ident.results()[1] != None and ident.results()[1] > 0:
                    cvid_v = cvid_v + 1

        cvid = 0
        for cs in range(Rt + 1):
            for rs in range(Ct, Ct + 1):
                xxx = cs * self._xsize + self._xmin
                yyy = self._ymax - rs * self._ysize
                ident = self.layer.dataProvider().identify(
                    QgsPointXY(xxx, yyy), QgsRaster.IdentifyFormatValue
                )

                # 2020-01-28 박: 변경은 했으나 맞는지 확인이 안됨
                if ident.results()[1] != None and ident.results()[1] > 0:
                    cvid = cvid + 1
        return cvid_v + cvid

    # 캔버스 클릭 이벤트 좌표 출력
    def canvasPressEvent(self, event):
        xx = event.pos().x()
        yy = event.pos().y()

        point = self.canvas.getCoordinateTransform().toMapCoordinates(xx, yy)
        if self.layer is not None:
            row, column = self.Point_To_RowColumn(point)
            _CVID = "Cvid: " + str(self.getCVID(row, column))
            self._XCOL = column
            self._YROW = row

            self._FYROW = self._YROW
            self._FXCOL = self._XCOL
            text = "xCol, yRow: " + str(row) + " , " + str(column)

            # 2020-01-28 박: 텍스트 박스 객체 넘기는게 되는지 모르겠음
            _get_set_control.GlobalLabel_SetText(text)

            self.Input_Cell_Value(row, column)
            if row < 0 or column < 0 or self._height <= column or self._width <= row:
                row = "out of extent"
                column = "out of extent"

            else:
                self.Cell_X_Center = (
                    self._extent.xMinimum() + self._xsize / 2 + self._xsize * (row)
                )
                self.Cell_Y_Center = (
                    self._ymax - self._ysize / 2 - self._ysize * (column)
                )

                FAc_ident = self.layer.dataProvider().identify(
                    QgsPointXY(self.Cell_X_Center, self.Cell_Y_Center),
                    QgsRaster.IdentifyFormatValue,
                )
                cw_text = self.channel_width_cal(FAc_ident.results()[1])

                self._Cnavas_Click_X = self.Cell_X_Center
                self._Cnavas_Click_Y = self.Cell_Y_Center
                if (
                    self.Cell_X_Center <= self._xmax
                    or self._xmin <= self.Cell_X_Center
                    or self.Cell_Y_Center <= self._ymax
                    or self._ymin <= self.Cell_Y_Center
                ):
                    self.post_vertex_remove()
                    self.create_vertex(self.Cell_X_Center, self.Cell_Y_Center)

        else:
            row = "no raster"
            column = "no raster"
            MsInfo("{0}, {1}".format(str(row), str(column)))

    def Input_Cell_Value(self, x, y):
        # Cell Info Flow 그룹 박스 데이터 내용
        CellCount = self._wsinfo.cellCountInWatershed
        CellType_Result = self._wsinfo.cellFlowTypeACell(x, y)
        Stream_Result = self._wsinfo.streamValue(x, y)
        FD_Result = self._wsinfo.flowDirection(x, y)
        FA_Result = self._wsinfo.flowAccumulation(x, y)
        Slop_Result = self._wsinfo.slope(x, y)
        watershed = self._wsinfo.watershedID(x, y)

        _get_set_control.GlobalControl_SetValue(
            str(CellCount),
            str(CellType_Result.decode("utf-8")),
            str(Stream_Result),
            FD_Result.decode("utf-8"),
            str(FA_Result),
            str(Slop_Result),
            str(watershed),
        )

        Texture_Result = self._wsinfo.soilTextureValue(x, y)

        # Cell Info Depth 그룹 박스 테이터 내용
        Depth_Result = self._wsinfo.soilDepthValue(x, y)

        # Cell Info Landcover 그룹 박스 테이터 내용
        Landcover_Result = self._wsinfo.landCoverValue(x, y)

        # 메모리에서 불러오는 것으로 변경 해야함 우선은 진행
        if self._GreenAmptCount > 1:
            for GreenAmpt in self._xmltodict["GRMProject"]["GreenAmptParameter"]:
                GridValue = GreenAmpt["GridValue"]
                if str(Texture_Result) == GridValue:
                    GRMCode = GreenAmpt["GRMCode"]
                    Porosity = GreenAmpt["Porosity"]
                    EffectivePorosity = GreenAmpt["EffectivePorosity"]
                    WFSoilSuctionHead = GreenAmpt["WFSoilSuctionHead"]
                    HydraulicConductivity = GreenAmpt["HydraulicConductivity"]
                    _get_set_control.GlobalControl_texture_SetValue(
                        GridValue,
                        GRMCode,
                        Porosity,
                        EffectivePorosity,
                        WFSoilSuctionHead,
                        HydraulicConductivity,
                    )
                    break
                elif Texture_Result is None or Texture_Result == "":
                    break
        elif self._GreenAmptCount == 1:
            GridValue = self._xmltodict["GRMProject"]["GreenAmptParameter"]["GridValue"]
            if str(Texture_Result) == GridValue:
                GRMCode = self._xmltodict["GRMProject"]["GreenAmptParameter"]["GRMCode"]
                Porosity = self._xmltodict["GRMProject"]["GreenAmptParameter"][
                    "Porosity"
                ]
                EffectivePorosity = self._xmltodict["GRMProject"]["GreenAmptParameter"][
                    "EffectivePorosity"
                ]
                WFSoilSuctionHead = self._xmltodict["GRMProject"]["GreenAmptParameter"][
                    "WFSoilSuctionHead"
                ]
                HydraulicConductivity = self._xmltodict["GRMProject"][
                    "GreenAmptParameter"
                ]["HydraulicConductivity"]
                _get_set_control.GlobalControl_texture_SetValue(
                    GridValue,
                    GRMCode,
                    Porosity,
                    EffectivePorosity,
                    WFSoilSuctionHead,
                    HydraulicConductivity,
                )

        if self._SoilDepthCount > 1:
            for SoilDepth in self._xmltodict["GRMProject"]["SoilDepth"]:
                GridValue = SoilDepth["GridValue"]
                if str(Depth_Result) == GridValue:
                    GRMCode = SoilDepth["GRMCode"]
                    # 2020-05-27 박: 변경됨
                    SoilDepth = SoilDepth["SoilDepth_cm"]
                    _get_set_control.GlobalControl_Depth_SetValue(
                        GridValue, GRMCode, SoilDepth
                    )
                    break
                elif Depth_Result is None or Depth_Result == "":
                    break

        elif self._SoilDepthCount == 1:
            GridValue = self._xmltodict["GRMProject"]["SoilDepth"]["GridValue"]
            if str(Depth_Result) == GridValue:
                GRMCode = self._xmltodict["GRMProject"]["SoilDepth"]["GRMCode"]
                SoilDepth = self._xmltodict["GRMProject"]["SoilDepth"]["SoilDepth_cm"]
                _get_set_control.GlobalControl_Depth_SetValue(
                    GridValue, GRMCode, SoilDepth
                )

        if self._LandCoverCount > 1:
            for LandCover in self._xmltodict["GRMProject"]["LandCover"]:
                GridValue = LandCover["GridValue"]
                if str(Landcover_Result) == GridValue:
                    GRMCode = LandCover["GRMCode"]
                    RoughnessCoefficient = LandCover["RoughnessCoefficient"]
                    ImperviousRatio = LandCover["ImperviousRatio"]
                    CanopyRatio = LandCover["CanopyRatio"]
                    InterceptionMaxWaterCanopy_mm = LandCover[
                        "InterceptionMaxWaterCanopy_mm"
                    ]
                    _get_set_control.GlobalControl_Landcover_SetValue(
                        GridValue,
                        GRMCode,
                        RoughnessCoefficient,
                        ImperviousRatio,
                        CanopyRatio,
                        InterceptionMaxWaterCanopy_mm,
                    )
                    break
                elif Landcover_Result is None or Landcover_Result == "":
                    break

        elif self._LandCoverCount == 1:
            GridValue = self._xmltodict["GRMProject"]["LandCover"]["GridValue"]
            if str(Depth_Result) == GridValue:
                GRMCode = self._xmltodict["GRMProject"]["LandCover"]["GRMCode"]
                RoughnessCoefficient = self._xmltodict["GRMProject"]["LandCover"][
                    "RoughnessCoefficient"
                ]
                ImperviousRatio = self._xmltodict["GRMProject"]["LandCover"][
                    "ImperviousRatio"
                ]
                CanopyRatio = self._xmltodict["GRMProject"]["LandCover"]["CanopyRatio"]
                InterceptionMaxWaterCanopy_mm = self._xmltodict["GRMProject"][
                    "LandCover"
                ]["InterceptionMaxWaterCanopy_mm"]
                _get_set_control.GlobalControl_Landcover_SetValue(
                    GridValue,
                    GRMCode,
                    RoughnessCoefficient,
                    ImperviousRatio,
                    CanopyRatio,
                    InterceptionMaxWaterCanopy_mm,
                )

    def Point_To_RowColumn(self, point):
        column = int(((self._ymax - point.y()) / self._ysize))
        row = int(((point.x() - self._xmin) / self._xsize))
        return row, column

    def canvasMoveEvent(self, event):
        x = event.pos().x()
        y = event.pos().y()
        point = self.canvas.getCoordinateTransform().toMapCoordinates(x, y)

    def canvasReleaseEvent(self, event):
        # Get the click
        x = event.pos().x()
        y = event.pos().y()
        point = self.canvas.getCoordinateTransform().toMapCoordinates(x, y)

    def activate(self):
        pass

    def deactivate(self):
        pass

    def isZoomTool(self):
        return False

    def isTransient(self):
        return False

    def isEditTool(self):
        return True

    # canvas event
    def ZoomtoExtent(self):
        self.canvas.zoomToFullExtent()
        self.canvas.refresh()

    def ZoomtoNextExtent(self):
        self.canvas.zoomToNextExtent()
        self.canvas.refresh()

    def ZoomtoPrevious(self):
        self.canvas.zoomToPreviousExtent()
        self.canvas.refresh()

    def canvas_zoomIn(self):
        actionZoomIn = QAction(self)
        self.toolZoomIn = QgsMapToolZoom(self.canvas, False)  # false = in
        self.toolZoomIn.setAction(actionZoomIn)
        self.canvas.setMapTool(self.toolZoomIn)
        self.canvas.refresh()

    def canvas_zoomOut(self):
        actionZoomOut = QAction(self)
        self.toolZoomOut = QgsMapToolZoom(self.canvas, True)  # True = out
        self.toolZoomOut.setAction(actionZoomOut)
        self.canvas.setMapTool(self.toolZoomOut)
        self.canvas.refresh()

    def canvas_pan(self):
        actionPan = QAction(self)
        self.toolPan = QgsMapToolPan(self.canvas)
        self.toolPan.setAction(actionPan)
        self.canvas.setMapTool(self.toolPan)

    #
    #     #2017/11/23----------------------
    def channel_width_cal(self, FAcvalue):
        # mw에서는 line edit 값을 바꿀 수 있고 그에 따라 결과 값이 바뀜. 일단 여기는 이렇세 처리함
        c = float(1.698)
        d = float(0.318)
        e = float(0.5)

        # FAc 는 cell 값, Slope는 gmp의 MinSlopeChBed 값임
        slope = float(0.0005)

        width = (
            c
            * pow((FAcvalue * (self._xsize * self._xsize / 1000000)), d)
            / pow(slope, e)
        )
        try:
            User_Cw = "%.3f" % width
        except Exception as e:
            return "0"
        return str(User_Cw)
