Client/Desktop/KMBIM3.0/23.10.18/Cmd/SheetLink/Form_SheetLink.cs

1373 lines
61 KiB
C#

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using Autodesk.Revit.DB;
using Autodesk.Revit.DB.Plumbing;
using Autodesk.Revit.UI;
using KDCS.Utils;
using KMBIM.Revit.Tools.Cmd.Assembly;
using Microsoft.Office.Interop.Excel;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Excel = Microsoft.Office.Interop.Excel;
using Color = System.Drawing.Color;
using Parameter = Autodesk.Revit.DB.Parameter;
using System.Threading;
namespace KMBIM
{
public partial class Form_SheetLink : System.Windows.Forms.Form
{
//리스트 뷰 아이템 저장 리스트
List<ListViewItem> m_LstViewItemLst = new List<ListViewItem>();
List<string> m_ChkLstBoxItemLst = new List<string>();
List<string> m_chkTextLst = new List<string>();
List<ParameterInfo> m_LstBoxItemLst = new List<ParameterInfo>();
List<ParameterInfo> m_SelLstBoxItemLst = new List<ParameterInfo>();
//public List<Element> ExtCatElemLst = null;
//public List<string> chkCatLst = null;
public Document m_doc;
public List<Category> m_Annocatlst = new List<Category>();
public List<Category> m_Modelcatlst = new List<Category>();
public List<Element> m_SchduleLst = new List<Element>();
List<ParameterInfo> m_ParamLst = new List<ParameterInfo>();
List<ParameterInfo> m_TotalParamLst = new List<ParameterInfo>();
//버튼 및 아이템 색상
Color PastelGreen = Color.FromArgb(241, 255, 223);
Color PastelYellow = Color.FromArgb(254, 250, 224);
Color PastelRed = Color.FromArgb(255, 226, 223);
//선택 아이템 색상
Color selitmClr = Color.FromArgb(203, 232, 246);
//열기,저장 버튼 색상
Color GreenBtnClr = Color.FromArgb(159, 221, 124);
//엑셀 Column Header 색상
Color ColHeaderClr = Color.FromArgb(217, 217, 217);
int gListViewLostFocusItem = -1;
public Form_SheetLink()
{
InitializeComponent();
}
private void Form_SheetLink_Load(object sender, EventArgs e)
{
ImageList ig = new ImageList();
//리소스에서 이미지 가져와 리스트 저장
Image inst = KMBIM.Revit.Tools.Properties.Resources.SL_instance;
Image ty = KMBIM.Revit.Tools.Properties.Resources.SL_type;
Image ro = KMBIM.Revit.Tools.Properties.Resources.SL_read_only;
ig.Images.Add(inst);
ig.Images.Add(ty);
ig.Images.Add(ro);
//리스트뷰의 small,large 이미지 리스트에 저장
listView_SL_Parameter.SmallImageList = ig;
listView_SL_Parameter.LargeImageList = ig;
listView_SL_SelParameter.SmallImageList = ig;
listView_SL_SelParameter.LargeImageList = ig;
//버튼 색상 지정
btn_Instance.BackColor = PastelGreen;
btn_Type.BackColor = PastelYellow;
btn_readOnly.BackColor = PastelRed;
btn_SL_Import.BackColor = GreenBtnClr;
btn_SL_Export.BackColor = GreenBtnClr;
////체크박스리스트 카테고리 문자열리스트로 반환
//foreach (Category cat in m_Modelcatlst)
//{
// chkLst_SL_Category.Items.Add(cat.Name);
// m_ChkLstBoxItemLst.Add(cat.Name);
//}
string lbltxt = string.Format("선택된 카테고리 : {0} | 검색된 매개변수 : {1} | 선택된 매개변수 : {2}",
chkLst_SL_Category.CheckedItems.Count, listView_SL_Parameter.Items.Count, listView_SL_Parameter.SelectedItems.Count);
lbl_SL_SelCnt.Text = lbltxt;
//리스트뷰 아이템 리스트에 저장
m_LstViewItemLst.AddRange(listView_SL_Parameter.Items.Cast<ListViewItem>());
//매개변수 리스트뷰에서 가로 스크롤바 제거하기 위해 첫번째 컬럼 넓이 줄임.
listView_SL_Parameter.Columns[0].Width = listView_SL_Parameter.Width - 4 - SystemInformation.VerticalScrollBarWidth;
}
///////////////////
//////////////////////////////////카테고리 체크박스 리스트//////////////////////////////////////
///////////////////
#region 카테고리 이벤트
//체크박스 전체 카테고리
private void chk_SL_TotalCategory_CheckedChanged(object sender, EventArgs e)
{
chkLst_SL_Category.Items.Clear();
foreach (var itm in m_ChkLstBoxItemLst)
chkLst_SL_Category.Items.Add(itm, true);
chkLst_SL_Category.SelectedIndex = 0;
//개수 라벨 업데이트
SetLabelText(chkLst_SL_Category.CheckedItems.Count, listView_SL_Parameter.Items.Count, listView_SL_Parameter.SelectedItems.Count);
}
//카테고리 체크박스리스트 선택 시
private void chkLst_SL_Category_SelectedIndexChanged(object sender, EventArgs e)
{
m_chkTextLst.Clear();
listView_SL_Parameter.Items.Clear();
m_LstBoxItemLst.Clear();
m_SelLstBoxItemLst.Clear();
//체크박스리스트 체크 값 리스트 저장
for (int i = 0; i < chkLst_SL_Category.Items.Count; i++)
{
if (chkLst_SL_Category.GetItemChecked(i))
m_chkTextLst.Add(chkLst_SL_Category.Items[i].ToString());
}
GetParamLst(m_chkTextLst, m_Modelcatlst, ref m_ParamLst, ref m_TotalParamLst);
//리스트 뷰 매개변수 리스트 추가
foreach (ParameterInfo info in m_ParamLst)
{
if (info.IsReadOnly == true)
listView_SL_Parameter.Items.Add(info.m_ParamName, 2);
else
{
if (info.IsType == true)
listView_SL_Parameter.Items.Add(info.m_ParamName, 1);
else
listView_SL_Parameter.Items.Add(info.m_ParamName, 0);
}
}
List<ListViewItem> m_delLviLst = new List<ListViewItem>();
//선택한 매개변수의 리스트가 체크된 카테고리에 해당되지 않으면 삭제
for (int i = 0; i < listView_SL_SelParameter.Items.Count; i++)
{
ListViewItem Lvi = listView_SL_SelParameter.Items[i];
bool b_Exist = false;
foreach (ParameterInfo info in m_TotalParamLst)
{
if (Lvi.Text == info.m_ParamName)
{
b_Exist = true;
break;
}
}
//카테고리 체크할 때마다 선택한 매개변수 목록이 사용 가능한 매개변수 삭제 목록에 추가
if (b_Exist == false)
m_delLviLst.Add(Lvi);
}
//삭제 목록에 있는 리스트 삭제
foreach (var Lvi in m_delLviLst)
listView_SL_SelParameter.Items.Remove(Lvi);
//사용 가능한 매개변수 리스트뷰 이름 리스트에 저장
foreach (ParameterInfo info in m_ParamLst)
m_LstBoxItemLst.Add(info);
//개수 라벨 업데이트
SetLabelText(chkLst_SL_Category.CheckedItems.Count, listView_SL_Parameter.Items.Count, listView_SL_Parameter.SelectedItems.Count);
}
//카테고리 검색 텍스트박스 변경 이벤트
private void txt_SL_CatSearch_TextChanged(object sender, EventArgs e)
{
chkLst_SL_Category.Items.Clear();
foreach (string str in m_ChkLstBoxItemLst)
{
if (str.StartsWith(txt_SL_CatSearch.Text, StringComparison.CurrentCultureIgnoreCase) || txt_SL_CatSearch.Text == "검색..")
chkLst_SL_Category.Items.Add(str);
}
//if (chkLst_SL_Category.Items.Count > 0)
//{
// foreach (string chkedItm in m_chkTextLst)
// {
// foreach (var chkItm in chkLst_SL_Category.Items)
// {
// if (chkItm.ToString() == chkedItm)
// {
// int idx = chkLst_SL_Category.Items.IndexOf(chkItm);
// chkLst_SL_Category.SetItemChecked(idx, true);
// }
// }
// }
//}
}
//카테고리 검색 텍스트박스 선택 시 이벤트
private void txt_SL_CatSearch_MouseClick(object sender, MouseEventArgs e)
{
if(txt_SL_CatSearch.Text =="검색..")
txt_SL_CatSearch.Text = "";
}
private void txt_SL_CatSearch_Leave(object sender, EventArgs e)
{
//if(txt_SL_CatSearch.Text=="")
// txt_SL_CatSearch.Text = "검색..";
}
//체크박스 미사용 체크박스 숨기기
private void chk_SL_HideUnChk_CheckedChanged(object sender, EventArgs e)
{
if (chk_SL_HideUnChk.Checked == true)
{
chkLst_SL_Category.Items.Clear();
//체크된 항목만 카테고리 리스트에 저장
foreach (string itm in m_chkTextLst)
chkLst_SL_Category.Items.Add(itm);
//새로 추가된 리스트 항목 모두 체크로 표시
for (int i = 0; i < chkLst_SL_Category.Items.Count; i++)
chkLst_SL_Category.SetItemChecked(i, true);
}
else
{
chkLst_SL_Category.Items.Clear();
//카테고리 항목 모두 리스트에 저장
foreach (string itm in m_ChkLstBoxItemLst)
chkLst_SL_Category.Items.Add(itm);
foreach (string itm in m_chkTextLst)
{
int idx = chkLst_SL_Category.Items.IndexOf(itm);
chkLst_SL_Category.SetItemChecked(idx, true);
}
}
}
#endregion
///////////////////
//////////////////////////////////사용 가능한 매개변수 리스트뷰//////////////////////////////////////
///////////////////
#region 사용 가능한 매개변수 이벤트
//파라미터 검색 텍스트박스 변경 이벤트
private void txt_SL_ParamSearch_TextChanged(object sender, EventArgs e)
{
listView_SL_Parameter.Items.Clear();
foreach(ParameterInfo info in m_LstBoxItemLst)
{
if (info.m_ParamName.StartsWith(txt_SL_ParamSearch.Text, StringComparison.CurrentCultureIgnoreCase) || txt_SL_ParamSearch.Text == "검색..")
{
if (info.IsReadOnly == true)
listView_SL_Parameter.Items.Add(info.m_ParamName, 2);
else
{
if (info.IsType == true)
listView_SL_Parameter.Items.Add(info.m_ParamName, 1);
else
listView_SL_Parameter.Items.Add(info.m_ParamName, 0);
}
}
}
}
//파라미터 검색 텍스트박스 선택 시 이벤트
private void txt_SL_ParamSearch_MouseClick(object sender, MouseEventArgs e)
{
txt_SL_ParamSearch.Text = "";
//if (txt_SL_ParamSearch.Text.Contains("검색..")==true)
// txt_SL_ParamSearch.Text = "";
//else if (txt_SL_ParamSearch.Text == "")
// txt_SL_ParamSearch.Text = "검색..";
}
//파라미터 리스트뷰 선택 시
private void listView_SL_Parameter_SelectedIndexChanged(object sender, EventArgs e)
{
//개수 라벨 업데이트
SetLabelText(chkLst_SL_Category.CheckedItems.Count, listView_SL_Parameter.Items.Count, listView_SL_Parameter.SelectedItems.Count);
}
//파라미터 리스트 드로우아이템
private void listView_SL_Parameter_DrawItem(object sender, DrawListViewItemEventArgs e)
{
if (listView_SL_Parameter.Items.Count <= 0) return;
Brush drawBrush = Brushes.Black;
//e.DrawDefault=true;
StringFormat sf = new StringFormat();
sf.LineAlignment = StringAlignment.Center;
sf.Alignment = StringAlignment.Near;
var SubItems = listView_SL_Parameter.Items[e.ItemIndex];
foreach (var info in m_ParamLst)
{
if (info.m_ParamName == SubItems.Text)
{
if (info.IsReadOnly == true)
{
e.Graphics.FillRectangle(new SolidBrush(PastelRed), e.Item.Bounds);
e.Graphics.DrawString(SubItems.Text, e.Item.Font, drawBrush, e.Bounds, sf);
break;
}
else
{
if (info.IsType == true)
{
e.Graphics.FillRectangle(new SolidBrush(PastelYellow), e.Item.Bounds);
e.Graphics.DrawString(SubItems.Text, e.Item.Font, drawBrush, e.Bounds, sf);
break;
}
else
{
e.Graphics.FillRectangle(new SolidBrush(PastelGreen), e.Item.Bounds);
e.Graphics.DrawString(SubItems.Text, e.Item.Font, drawBrush, e.Bounds, sf);
break;
}
}
}
}
if (e.Item.Selected)
{
if (gListViewLostFocusItem == e.Item.Index)
{
e.Item.ForeColor = Color.Black;
e.Item.BackColor = selitmClr;
gListViewLostFocusItem = -1;
}
else if (listView_SL_Parameter.Focused)
{
e.Item.ForeColor = SystemColors.HighlightText;
e.Item.BackColor = SystemColors.Highlight;
}
}
else
{
e.Item.ForeColor = listView_SL_Parameter.ForeColor;
e.Item.BackColor = listView_SL_Parameter.BackColor;
}
e.DrawFocusRectangle();
e.DrawBackground();
e.DrawText();
e.DrawDefault = true;
}
private void listView_SL_Parameter_Leave(object sender, EventArgs e)
{
if (listView_SL_Parameter.Items.Count > 0)
gListViewLostFocusItem = listView_SL_Parameter.FocusedItem.Index;
}
//버튼 인스턴스
private void btn_Instance_Click(object sender, EventArgs e)
{
listView_SL_Parameter.Items.Clear();
//Instance 리스트
foreach (var info in m_ParamLst)
{
if (info.IsReadOnly == false && info.IsType == false)
listView_SL_Parameter.Items.Add(info.m_ParamName, 0);
}
//Type 리스트
foreach (var info in m_ParamLst)
{
if (info.IsReadOnly == false && info.IsType == true)
listView_SL_Parameter.Items.Add(info.m_ParamName, 1);
}
//Read-Only 리스트
foreach (var info in m_ParamLst)
{
if (info.IsReadOnly == true)
listView_SL_Parameter.Items.Add(info.m_ParamName, 2);
}
}
//버튼 타입
private void btn_Type_Click(object sender, EventArgs e)
{
listView_SL_Parameter.Items.Clear();
//Type 리스트
foreach (var info in m_ParamLst)
{
if (info.IsReadOnly == false && info.IsType == true)
listView_SL_Parameter.Items.Add(info.m_ParamName, 1);
}
//Instance 리스트
foreach (var info in m_ParamLst)
{
if (info.IsReadOnly == false && info.IsType == false)
listView_SL_Parameter.Items.Add(info.m_ParamName, 0);
}
//Read-Only 리스트
foreach (var info in m_ParamLst)
{
if (info.IsReadOnly == true)
listView_SL_Parameter.Items.Add(info.m_ParamName, 2);
}
}
//버튼 읽기전용
private void btn_readOnly_Click(object sender, EventArgs e)
{
listView_SL_Parameter.Items.Clear();
//Read-Only 리스트
foreach (var info in m_ParamLst)
{
if (info.IsReadOnly == true)
listView_SL_Parameter.Items.Add(info.m_ParamName, 2);
}
//Instance 리스트
foreach (var info in m_ParamLst)
{
if (info.IsReadOnly == false && info.IsType == false)
listView_SL_Parameter.Items.Add(info.m_ParamName, 0);
}
//Type 리스트
foreach (var info in m_ParamLst)
{
if (info.IsReadOnly == false && info.IsType == true)
listView_SL_Parameter.Items.Add(info.m_ParamName, 1);
}
}
#endregion
///////////////////
//////////////////////////////////선택한 매개변수 리스트뷰//////////////////////////////////////
///////////////////
#region 선택한 매개변수 이벤트
//텍스트박스 선택한 매개변수 검색
private void txt_SL_SelParamSearch_TextChanged(object sender, EventArgs e)
{
listView_SL_SelParameter.Items.Clear();
foreach (ParameterInfo info in m_SelLstBoxItemLst)
{
if (info.m_ParamName.StartsWith(txt_SL_SelParamSearch.Text, StringComparison.CurrentCultureIgnoreCase) || txt_SL_SelParamSearch.Text == "검색..")
{
if (info.IsReadOnly == true)
listView_SL_SelParameter.Items.Add(info.m_ParamName, 2);
else
{
if (info.IsType == true)
listView_SL_SelParameter.Items.Add(info.m_ParamName, 1);
else
listView_SL_SelParameter.Items.Add(info.m_ParamName, 0);
}
}
}
}
//텍스트박스 클릭 시 이벤트
private void txt_SL_SelParamSearch_MouseClick(object sender, MouseEventArgs e)
{
txt_SL_SelParamSearch.Text = "";
//if (txt_SL_SelParamSearch.Text == "검색..")
// txt_SL_SelParamSearch.Text = "";
//else if (txt_SL_SelParamSearch.Text == "")
// txt_SL_SelParamSearch.Text = "검색..";
}
//선택한 매개변수 리스트뷰로 추가
private void btn_SL_Add_Click(object sender, EventArgs e)
{
if (listView_SL_Parameter.SelectedItems.Count > 0)
{
List<ListViewItem> m_LviLst = new List<ListViewItem>();
for (int i = 0; i < listView_SL_Parameter.SelectedItems.Count; i++)
{
ListViewItem selitm = listView_SL_Parameter.SelectedItems[i];
m_LviLst.Add(selitm);
}
foreach (var Lvi in m_LviLst)
{
//선택한 매개변수 리스트에 추가
if (FindParameterInfo(m_LstBoxItemLst, Lvi.Text) != null)
m_SelLstBoxItemLst.Add(FindParameterInfo(m_LstBoxItemLst, Lvi.Text));
//사용 가능한 매개변수 리스트에서 삭제
if (FindParameterInfo(m_LstBoxItemLst, Lvi.Text) != null)
m_LstBoxItemLst.Remove(FindParameterInfo(m_LstBoxItemLst, Lvi.Text));
//사용 가능한 매개변수에 매개변수 삭제
listView_SL_Parameter.Items.Remove(Lvi);
//선택한 매개변수에 매개변수 추가
listView_SL_SelParameter.Items.Add(Lvi);
}
}
}
//선택한 매개변수 리스트뷰에서 제거
private void btn_SL_Minus_Click(object sender, EventArgs e)
{
if (listView_SL_SelParameter.SelectedItems.Count > 0)
{
foreach (ListViewItem Lvi in listView_SL_SelParameter.Items)
{
//사용 가능한 매개변수 리스트에 추가
if (FindParameterInfo(m_SelLstBoxItemLst, Lvi.Text) != null)
m_LstBoxItemLst.Add(FindParameterInfo(m_SelLstBoxItemLst, Lvi.Text));
//선택한 매개변수 리스트에서 삭제
if (FindParameterInfo(m_SelLstBoxItemLst, Lvi.Text) != null)
m_SelLstBoxItemLst.Remove(FindParameterInfo(m_SelLstBoxItemLst, Lvi.Text));
//선택한 매개변수에 매개변수 삭제
listView_SL_SelParameter.Items.Remove(Lvi);
//사용 가능한 매개변수에 매개변수 추가
listView_SL_Parameter.Items.Add(Lvi);
}
//사용 가능한 매개변수 정렬
listView_SL_Parameter.Sorting = SortOrder.Ascending;
}
//// 리스트뷰 이벤트 발생으로 인해 매개변수 값이 변경될 때 refresh함수 - 검색에 쓰임
//RefreshParameterList(listView_SL_Parameter, m_ParamLst, ref m_LstBoxItemLst);
//// 리스트뷰 이벤트 발생으로 인해 매개변수 값이 변경될 때 refresh함수 - 검색에 쓰임
//RefreshParameterList(listView_SL_SelParameter, m_ParamLst, ref m_SelLstBoxItemLst);
}
//리스트뷰에서 선택한 값 첫번쨰로 올리기
private void btn_SL_Top_Click(object sender, EventArgs e)
{
if (listView_SL_SelParameter.SelectedItems.Count > 0)
{
List<ListViewItem> LviLst = new List<ListViewItem>();
for (int i = 0; i < listView_SL_SelParameter.SelectedItems.Count; i++)
{
ListViewItem selected = listView_SL_SelParameter.SelectedItems[i];
LviLst.Add(selected);
}
//역순으로 넣기 위해 Reverse
LviLst.Reverse();
foreach (ListViewItem lvi in LviLst)
{
//검색 리스트 값 적용
if (FindParameterInfo(m_SelLstBoxItemLst, lvi.Text) != null)
{
var info = FindParameterInfo(m_SelLstBoxItemLst, lvi.Text);
m_SelLstBoxItemLst.Remove(info);
m_SelLstBoxItemLst.Insert(0, info);
}
listView_SL_SelParameter.Items.Remove(lvi);
listView_SL_SelParameter.Items.Insert(0, lvi);
}
}
//// 리스트뷰 이벤트 발생으로 인해 매개변수 값이 변경될 때 refresh함수 - 검색에 쓰임
//RefreshParameterList(listView_SL_SelParameter, m_ParamLst, ref m_SelLstBoxItemLst);
}
//리스트뷰에서 선택한 값 한 칸 위로 올리기
private void btn_SL_Up_Click(object sender, EventArgs e)
{
if (listView_SL_SelParameter.SelectedItems.Count > 0)
{
for (int i = 0; i < listView_SL_SelParameter.SelectedItems.Count; i++)
{
ListViewItem selected = listView_SL_SelParameter.SelectedItems[i];
int idx = selected.Index;
int total = listView_SL_SelParameter.Items.Count;
if (idx == 0)
{
//listView_SL_SelParameter.Items.Remove(selected);
//listView_SL_SelParameter.Items.Insert(total - 1, selected);
}
else
{
//검색 리스트 값 적용
if (FindParameterInfo(m_SelLstBoxItemLst, selected.Text) != null)
{
var info = FindParameterInfo(m_SelLstBoxItemLst, selected.Text);
m_SelLstBoxItemLst.Remove(info);
m_SelLstBoxItemLst.Insert(idx - 1, info);
}
listView_SL_SelParameter.Items.Remove(selected);
listView_SL_SelParameter.Items.Insert(idx - 1, selected);
}
}
}
//// 리스트뷰 이벤트 발생으로 인해 매개변수 값이 변경될 때 refresh함수 - 검색에 쓰임
//RefreshParameterList(listView_SL_SelParameter, m_ParamLst, ref m_SelLstBoxItemLst);
}
//리스트뷰에서 선택한 값 한 칸 아래로 내리기
private void btn_SL_Down_Click(object sender, EventArgs e)
{
if (listView_SL_SelParameter.SelectedItems.Count > 0)
{
for (int i = 0; i < listView_SL_SelParameter.SelectedItems.Count; i++)
{
ListViewItem selected = listView_SL_SelParameter.SelectedItems[i];
int idx = selected.Index;
int total = listView_SL_SelParameter.Items.Count;
if (idx == total - 1)
{
//listView_SL_SelParameter.Items.Remove(selected);
//listView_SL_SelParameter.Items.Insert(0, selected);
}
else
{
//검색 리스트 값 적용
if (FindParameterInfo(m_SelLstBoxItemLst, selected.Text) != null)
{
var info = FindParameterInfo(m_SelLstBoxItemLst, selected.Text);
m_SelLstBoxItemLst.Remove(info);
m_SelLstBoxItemLst.Insert(idx + 1, info);
}
listView_SL_SelParameter.Items.Remove(selected);
listView_SL_SelParameter.Items.Insert(idx + 1, selected);
}
}
}
//// 리스트뷰 이벤트 발생으로 인해 매개변수 값이 변경될 때 refresh함수 - 검색에 쓰임
//RefreshParameterList(listView_SL_SelParameter, m_ParamLst, ref m_SelLstBoxItemLst);
}
//리스트뷰에서 선택한 값 마지막으로 내리기
private void btn_SL_Bottom_Click(object sender, EventArgs e)
{
if (listView_SL_SelParameter.SelectedItems.Count > 0)
{
List<ListViewItem> LviLst = new List<ListViewItem>();
for (int i = 0; i < listView_SL_SelParameter.SelectedItems.Count; i++)
{
ListViewItem selected = listView_SL_SelParameter.SelectedItems[i];
LviLst.Add(selected);
}
int total = listView_SL_SelParameter.Items.Count;
foreach (ListViewItem lvi in LviLst)
{
//검색 리스트 값 적용
if (FindParameterInfo(m_SelLstBoxItemLst, lvi.Text) != null)
{
var info = FindParameterInfo(m_SelLstBoxItemLst, lvi.Text);
m_SelLstBoxItemLst.Remove(info);
m_SelLstBoxItemLst.Insert(total - 1, info);
}
listView_SL_SelParameter.Items.Remove(lvi);
listView_SL_SelParameter.Items.Insert(total - 1, lvi);
}
}
//// 리스트뷰 이벤트 발생으로 인해 매개변수 값이 변경될 때 refresh함수 - 검색에 쓰임
//RefreshParameterList(listView_SL_SelParameter, m_ParamLst, ref m_SelLstBoxItemLst);
}
//선택한 매개변수 리스트뷰 초기화
private void btn_SL_CatReset_Click(object sender, EventArgs e)
{
if (listView_SL_SelParameter.Items.Count > 0)
{
List<ListViewItem> LviLst = new List<ListViewItem>();
for (int i = 0; i < listView_SL_SelParameter.Items.Count; i++)
{
ListViewItem Lvi = listView_SL_SelParameter.Items[i];
//선택한 매개변수 아이템 리스트에 저장
LviLst.Add(Lvi);
}
//선택한 매개변수 아이템 초기화
listView_SL_SelParameter.Items.Clear();
//선택한 매개변수 아이템 -> 사용 가능한 매개변수 리스트로 이동
foreach (var lvi in LviLst)
{
//사용 가능한 매개변수 리스트로 옮기기.
listView_SL_Parameter.Items.Add(lvi);
}
//사용 가능한 매개변수 정렬
listView_SL_Parameter.Sorting = SortOrder.Ascending;
//검색에 쓰이는 리스트 초기화
m_LstBoxItemLst.Clear();
m_LstBoxItemLst.AddRange(m_ParamLst);
m_SelLstBoxItemLst.Clear();
//개수 라벨 업데이트
SetLabelText(chkLst_SL_Category.CheckedItems.Count, listView_SL_Parameter.Items.Count, listView_SL_Parameter.SelectedItems.Count);
}
//// 리스트뷰 이벤트 발생으로 인해 매개변수 값이 변경될 때 refresh함수 - 검색에 쓰임
//RefreshParameterList(listView_SL_SelParameter, m_ParamLst, ref m_SelLstBoxItemLst);
}
#endregion
private void GetCategoryLst(int ViewMode, ref List<Category> Modelcatlst, ref List<Category> Annocatlst, ref List<Element> SchduleLst)
{
Modelcatlst.Clear();
Annocatlst.Clear();
SchduleLst.Clear();
//List<Category> Annocatlst = new List<Category>();
//List<Category> Modelcatlst = new List<Category>();
//전체
if (ViewMode == 0)
{
//현재 도면에 존재하는 모델,주석 카테고리 리스트 추출하기
foreach (Category c in m_doc.Settings.Categories)
{
bool foundInstance = false;
foreach (Element elm in new FilteredElementCollector(m_doc)
.WhereElementIsNotElementType()
.OfCategoryId(c.Id))
{
foundInstance = true;
break;
}
if (foundInstance)
{
if (c.CategoryType == CategoryType.Annotation)
Annocatlst.Add(c);
else if (c.CategoryType == CategoryType.Model)
{
if (c.AllowsBoundParameters == true)
{
if (c.Id.IntegerValue == (int)BuiltInCategory.OST_ProjectInformation
|| c.Id.IntegerValue == (int)BuiltInCategory.OST_RvtLinks) { }
else
Modelcatlst.Add(c);
}
}
else if (c.CategoryType == CategoryType.Internal)
if (c.Id.IntegerValue != (int)BuiltInCategory.OST_Schedules)
Modelcatlst.Add(c);
}
}
//스케쥴 리스트
SchduleLst = new FilteredElementCollector(m_doc)
.WhereElementIsNotElementType()
.OfCategory(BuiltInCategory.OST_Schedules).ToList();
}
else if (ViewMode == 1)//현재 뷰
{
//현재 도면에 존재하는 모델,주석 카테고리 리스트 추출하기
foreach (Category c in m_doc.Settings.Categories)
{
bool foundInstance = false;
foreach (Element elm in new FilteredElementCollector(m_doc, m_doc.ActiveView.Id)
.WhereElementIsNotElementType()
.OfCategoryId(c.Id))
{
foundInstance = true;
break;
}
if (foundInstance)
{
if (c.CategoryType == CategoryType.Annotation)
Annocatlst.Add(c);
else if (c.CategoryType == CategoryType.Model)
{
if (c.AllowsBoundParameters == true)
{
if (c.Id.IntegerValue == (int)BuiltInCategory.OST_ProjectInformation
|| c.Id.IntegerValue == (int)BuiltInCategory.OST_RvtLinks) { }
else
Modelcatlst.Add(c);
}
}
else if (c.CategoryType == CategoryType.Internal)
if (c.Id.IntegerValue != (int)BuiltInCategory.OST_Schedules)
Modelcatlst.Add(c);
}
}
//스케쥴 리스트
SchduleLst = new FilteredElementCollector(m_doc, m_doc.ActiveView.Id)
.WhereElementIsNotElementType()
.OfCategory(BuiltInCategory.OST_Schedules).ToList();
}
//이름순 정렬
Annocatlst.Sort((a, b) => a.Name.CompareTo(b.Name));
Modelcatlst.Sort((a, b) => a.Name.CompareTo(b.Name));
SchduleLst.Sort((a, b) => a.Name.CompareTo(b.Name));
}
/// <summary>
/// 카테고리 리스트에 따른 중복제거된 리스트, 전체 리스트
/// </summary>
/// <param name="ChkCategoryNameLst"></param>체크된 항목 리스트
/// <param name="Model_cat_list"></param>카테고리 리스트
/// <param name="deduplParamLst"></param>중복제거된 매개변수 리스트
/// <param name="TotalParamLst"></param>모든 매개변수 리스트
private void GetParamLst(List<string> ChkCategoryNameLst, List<Category> Model_cat_list, ref List<ParameterInfo> deduplParamLst, ref List<ParameterInfo> TotalParamLst)
{
List<ParameterInfo> m_ParamInfolst = new List<ParameterInfo>();
foreach (string chkCatName in ChkCategoryNameLst)
{
foreach (Category mdlCat in Model_cat_list)
{
if (chkCatName == mdlCat.Name)
{
List<Element> selCatElemLst = new FilteredElementCollector(m_doc)
.WhereElementIsNotElementType().OfCategoryId(mdlCat.Id).ToList();
foreach (Element selCatElem in selCatElemLst)
{
var id = selCatElem.GetTypeId();
if (selCatElem.GetTypeId().IntegerValue != -1)
{
Element typeElem = m_doc.GetElement(selCatElem.GetTypeId());
if (typeElem.Parameters == null) continue;
foreach (Parameter param in typeElem.Parameters)
{
ParameterInfo pInfo = new ParameterInfo();
pInfo.m_ParamElement = typeElem;
pInfo.m_ParamName = param.Definition.Name;
pInfo.m_CategortName = chkCatName;
pInfo.m_StorageType = param.StorageType.ToString();
pInfo.IsType = true;
pInfo.IsReadOnly = param.IsReadOnly;
m_ParamInfolst.Add(pInfo);
}//foreach end
}
ParameterSet paramSet = selCatElem.Parameters;
foreach (Parameter param in paramSet)
{
//재료 카테고리에 HasValue = false 인 파라미터는 담지 않음.
if (mdlCat.Id.IntegerValue == (int)BuiltInCategory.OST_Materials && param.HasValue == false) continue;
ParameterInfo pInfo = new ParameterInfo();
pInfo.m_ParamElement = selCatElem;
pInfo.m_ParamName = param.Definition.Name;
pInfo.m_CategortName = chkCatName;
pInfo.m_StorageType = param.StorageType.ToString();
pInfo.IsType = false;
if (param.Id.IntegerValue == (int)BuiltInParameter.ELEM_TYPE_PARAM
|| param.Id.IntegerValue == (int)BuiltInParameter.ELEM_FAMILY_PARAM
|| param.Id.IntegerValue == (int)BuiltInParameter.ELEM_FAMILY_AND_TYPE_PARAM)
pInfo.IsReadOnly = true;
else
pInfo.IsReadOnly = param.IsReadOnly;
m_ParamInfolst.Add(pInfo);
}//foreach end
}//foreach end
//MessageBox.Show(selCatElemLst.Count.ToString(),selCatElemLst.First().Category.Name);
}
}//foreach end
}//foreach end
//매개변수와 카테고리 중복값 제외 모든 매개변수 리스트
TotalParamLst = m_ParamInfolst;
TotalParamLst = TotalParamLst.Distinct(new DistinctElement2()).ToList();
//매개변수 중복값 제외 매개변수 리스트 -> 사용가능한 매개변수 리스트용
m_ParamInfolst = m_ParamInfolst.Distinct(new DistinctElement()).ToList();
m_ParamInfolst.Sort((a, b) => a.m_ParamName.CompareTo(b.m_ParamName));
deduplParamLst = m_ParamInfolst;
return;
}
//하단 라벨 출력 함수
private void SetLabelText(int CheckedItemCnt, int TotalParamCnt, int SelectParamCnt)
{
string lbltxt = string.Format("선택된 카테고리 : {0} | 검색된 매개변수 : {1} | 선택된 매개변수 : {2}", CheckedItemCnt, TotalParamCnt, SelectParamCnt);
lbl_SL_SelCnt.Text = lbltxt;
}
public class ParameterInfo
{
public Element m_ParamElement;
public string m_ParamName;
public string m_CategortName;
public string m_StorageType;
public bool IsReadOnly;
public bool IsType;
}
private ParameterInfo FindParameterInfo(List<ParameterInfo> paramInfoLst, string ParamName)
{
ParameterInfo resInfo = null;
foreach (ParameterInfo info in paramInfoLst)
{
if (info.m_ParamName == ParamName)
{
resInfo = info;
break;
}
}
return resInfo;
}
private bool ExistParameterInfo(List<ParameterInfo> paramInfoLst, string ParamName)
{
return paramInfoLst.Any(ParameterInfo => ParameterInfo.m_ParamName == ParamName);
}
private class DistinctElement : IEqualityComparer<ParameterInfo>
{
bool IEqualityComparer<ParameterInfo>.Equals(ParameterInfo x, ParameterInfo y)
{
//throw new NotImplementedException();
return x.m_ParamName.Equals(y.m_ParamName);
}
int IEqualityComparer<ParameterInfo>.GetHashCode(ParameterInfo obj)
{
//throw new NotImplementedException();
return obj.m_ParamName.GetHashCode();
}
}
private class DistinctElement2 : IEqualityComparer<ParameterInfo>
{
bool IEqualityComparer<ParameterInfo>.Equals(ParameterInfo x, ParameterInfo y)
{
//throw new NotImplementedException();
if (x.m_ParamName.Equals(y.m_ParamName) && x.m_CategortName.Equals(y.m_CategortName))
return true;
else
return false;
//return x.m_ParamName.Equals(y.m_ParamName);
}
int IEqualityComparer<ParameterInfo>.GetHashCode(ParameterInfo obj)
{
//throw new NotImplementedException();
return obj.m_ParamName.GetHashCode();
}
}
private class DistinctCategoryElement : IEqualityComparer<ParameterInfo>
{
bool IEqualityComparer<ParameterInfo>.Equals(ParameterInfo x, ParameterInfo y)
{
//throw new NotImplementedException();
return x.m_CategortName.Equals(y.m_CategortName);
}
int IEqualityComparer<ParameterInfo>.GetHashCode(ParameterInfo obj)
{
//throw new NotImplementedException();
return obj.m_CategortName.GetHashCode();
}
}
//전체 라디오 버튼
private void rad_SL_Total_CheckedChanged(object sender, EventArgs e)
{
GetCategoryLst(0, ref m_Modelcatlst, ref m_Annocatlst, ref m_SchduleLst);
//중복값 제거
m_Modelcatlst = m_Modelcatlst.Distinct().ToList();
m_Annocatlst = m_Annocatlst.Distinct().ToList();
m_SchduleLst = m_SchduleLst.Distinct().ToList();
//체크박스리스트 초기화
chkLst_SL_Category.Items.Clear();
//체크박스리스트 카테고리 리스트 추가
foreach (Category cat in m_Modelcatlst)
{
chkLst_SL_Category.Items.Add(cat.Name);
m_ChkLstBoxItemLst.Add(cat.Name);
}
}
//현재 뷰 라디오 버튼
private void rad_SL_CurView_CheckedChanged(object sender, EventArgs e)
{
GetCategoryLst(1, ref m_Modelcatlst, ref m_Annocatlst, ref m_SchduleLst);
//중복값 제거
m_Modelcatlst = m_Modelcatlst.Distinct().ToList();
m_Annocatlst = m_Annocatlst.Distinct().ToList();
m_SchduleLst = m_SchduleLst.Distinct().ToList();
//체크박스리스트 초기화
chkLst_SL_Category.Items.Clear();
//체크박스리스트 카테고리 리스트 추가
foreach (Category cat in m_Modelcatlst)
{
chkLst_SL_Category.Items.Add(cat.Name);
m_ChkLstBoxItemLst.Add(cat.Name);
}
}
//선택 객체 라디오 버튼
private void Rad_SL_SelElem_CheckedChanged(object sender, EventArgs e)
{
}
//초기화 버튼
private void btn_SL_TotalReset_Click(object sender, EventArgs e)
{
listView_SL_SelParameter.Items.Clear();
listView_SL_Parameter.Items.Clear();
for (int i = 0; i < chkLst_SL_Category.Items.Count; i++)
{
if (chkLst_SL_Category.GetItemChecked(i) == true)
chkLst_SL_Category.SetItemChecked(i, false);
}
}
//데이터 열기 버튼
private void btn_SL_Import_Click(object sender, EventArgs e)
{
OpenFileDialog openFileDialog = new OpenFileDialog();
string location = "";
if (Reg.getReg("SL_FilePath") != "")
location = Reg.getReg("SL_FilePath");
else
location = Util.GetKMBIMLibraryFolder("Libraries\\SheetLink");
openFileDialog.Filter = "(*.xlsx)|*.xlsx";
openFileDialog.Title = "Open an Excel File";
openFileDialog.InitialDirectory = location;
if (openFileDialog.ShowDialog() != DialogResult.OK)
return;
if (openFileDialog.FileName != "")
{
Excel.Application excel = new Excel.Application();
Workbook workbook = null;
List<string> columnNames = new List<string>();
object[,] valueArray;
try
{
workbook = excel.Workbooks.Open(openFileDialog.FileName);
if (workbook.Worksheets != null && workbook.Worksheets.Count > 0)
{
Worksheet dataSheet = (Worksheet)workbook.Worksheets[1];
int cnt = workbook.Worksheets.Count;
Range rg = dataSheet.UsedRange;
valueArray = (object[,])rg.get_Value(XlRangeValueDataType.xlRangeValueDefault);
if (workbook != null)
{
workbook.Close();
excel.Quit();
}
int n = valueArray.GetLength(1);
//var aaa = valueArray.GetValue();
for (int row = 1; row < valueArray.GetLength(0); row++)
{
if (valueArray[row, 1] != null)
{
columnNames.Add(valueArray[row, 1].ToString());
}
}
}
}
catch
{
if (workbook != null)
{
workbook.Close();
excel.Quit();
}
}
}
}
//선택한 매개변수에 대한 ParameterInfo 값 추출 리스트 가져오기
private List<ParameterInfo> SelParamList_GetParameterInfo()
{
//선택된 매개변수 리스트
List<string> m_selParamLst = new List<string>();
foreach (ListViewItem lvi in listView_SL_SelParameter.Items)
m_selParamLst.Add(lvi.Text);
//m_ParamLst = 중복제거된 매개변수 리스트
//m_TotalParamLst = 모든 매개변수 리스트
List<ParameterInfo> m_selParamInfoLst = new List<ParameterInfo>();
foreach (string selParam in m_selParamLst)
{
foreach (ParameterInfo info in m_TotalParamLst)
{
if (selParam == info.m_ParamName)
{
m_selParamInfoLst.Add(info);
}
}
}
return m_selParamInfoLst;
}
//데이터 저장 버튼
private void btn_SL_Export_Click(object sender, EventArgs e)
{
CheckForIllegalCrossThreadCalls = false;
//선택한 매개변수에 대한 ParameterInfo 값 추출 리스트 가져오기
List<ParameterInfo> m_SelParamInfoLst = SelParamList_GetParameterInfo();
if (listView_SL_SelParameter.Items.Count == 0)
{
MessageBox.Show("선택된 데이터가 없습니다.", "Error");
return;
}
SaveFileDialog saveFileDialog = new SaveFileDialog();
if (chkLst_SL_Category.CheckedItems.Count == 1)
saveFileDialog.FileName = chkLst_SL_Category.CheckedItems[0].ToString() + ".xlsx";
else if (chkLst_SL_Category.CheckedItems.Count > 1)
{
saveFileDialog.FileName = "Result.xlsx";
}
saveFileDialog.Filter = "(*.xlsx)|*.xlsx";
saveFileDialog.Title = "Excel File Location";
if (saveFileDialog.ShowDialog() == DialogResult.OK)
{
if (saveFileDialog.FileName != "")
{
//저장할 때 사용한 경로 레지스트리에 저장
Reg.setReg("SL_FilePath", Path.GetDirectoryName(saveFileDialog.FileName));
List<ParameterInfo> m_ExportInfoLst = m_SelParamInfoLst;
List<ParameterInfo> m_CategoryInfoLst = m_ExportInfoLst.Distinct(new DistinctCategoryElement()).ToList();
try
{
bool isExport = false;
Excel.Application excel = new Excel.Application();
Excel.Workbook workbook = excel.Workbooks.Add(Type.Missing);
Excel.Worksheet worksheet = null;
foreach(var cat in m_CategoryInfoLst)
{
//시트 맨뒤에 추가하는 코드
worksheet = (Worksheet)workbook.Worksheets.Add(After: workbook.Worksheets.Item[workbook.Worksheets.Count]);
worksheet.Name = cat.m_CategortName;
worksheet.Cells[1, 1] = "Element ID\nCustom Parameter";
worksheet.Range[worksheet.Cells[1, 1], worksheet.Cells[1, 1]].ColumnWidth = 19.71;
int cellRowIdx = 1;
int cellColIdx = 2;
//행 헤드값
for(int col=0; col<m_ExportInfoLst.Count; col++)
{
if (cellRowIdx == 1 && m_ExportInfoLst[col].m_CategortName == cat.m_CategortName)
{
ParameterInfo pInfo = m_ExportInfoLst.ElementAt(col);
//column 문자에 따른 폭 자동 설정
worksheet.Range[worksheet.Cells[1, cellColIdx], worksheet.Cells[1, cellColIdx]].Columns.AutoFit();
//자동 넓이 + 2.5 추가
double colWidth = (double)worksheet.Range[worksheet.Cells[1, cellColIdx], worksheet.Cells[1, cellColIdx]].ColumnWidth;
worksheet.Range[worksheet.Cells[1, cellColIdx], worksheet.Cells[1, cellColIdx]].ColumnWidth = colWidth + 2.5;
//배경색 지정(그레이)
worksheet.Range[worksheet.Cells[1, cellColIdx], worksheet.Cells[1, cellColIdx]].Interior.Color = ColHeaderClr;
string tmp_colHeader = "";
if (pInfo.IsType == true)
tmp_colHeader += pInfo.m_ParamName + "\n" + pInfo.m_StorageType + "\n" + "Type";
else
tmp_colHeader += pInfo.m_ParamName + "\n" + pInfo.m_StorageType + "\n" + "Instance";
worksheet.Cells[cellRowIdx, cellColIdx++] = tmp_colHeader;
}
}
cellColIdx = 1;
cellRowIdx++;
FilteredElementCollector collector = new FilteredElementCollector(m_doc).WhereElementIsNotElementType();
IList<Element> collection = collector.OfCategory((BuiltInCategory)cat.m_ParamElement.Category.Id.IntegerValue).ToList();
//열 객체별 매개변수 값
for (int row = 0; row< collection.Count; row++)
{
//첫번째 col은 객체 id
worksheet.Cells[cellRowIdx, cellColIdx++] = collection[row].Id;
foreach(ParameterInfo info in m_ExportInfoLst)
{
if (info.m_CategortName == cat.m_CategortName)
{
Definition def = Util.GetDefinition(collection[row], info.m_ParamName);
Definition typeDef = Util.GetDefinition(m_doc.GetElement(collection[row].GetTypeId()), info.m_ParamName);
if (def != null)
{
Parameter param = collection[row].get_Parameter(def);
//배경색 지정
if (param.IsReadOnly == true)
worksheet.Range[worksheet.Cells[cellRowIdx, cellColIdx], worksheet.Cells[cellRowIdx, cellColIdx]].Interior.Color = PastelRed;
//유형,패밀리,패밀리 및 유형은 붉은색으로 강제 지정
if(param.Id.IntegerValue == (int)BuiltInParameter.ELEM_TYPE_PARAM
|| param.Id.IntegerValue == (int)BuiltInParameter.ELEM_FAMILY_PARAM
|| param.Id.IntegerValue == (int)BuiltInParameter.ELEM_FAMILY_AND_TYPE_PARAM)
worksheet.Range[worksheet.Cells[cellRowIdx, cellColIdx], worksheet.Cells[cellRowIdx, cellColIdx]].Interior.Color = PastelRed;
if (param.StorageType.ToString() == "Integer" || param.StorageType.ToString() == "String"
|| param.StorageType.ToString() == "ElementId" || param.StorageType.ToString() == "None")
worksheet.Cells[cellRowIdx, cellColIdx] = param.AsValueString();
else if (param.StorageType.ToString() == "Double")
worksheet.Cells[cellRowIdx, cellColIdx] = Unit.FeetToMM(param.AsDouble());
//if (param.AsValueString() != null)
//{
// worksheet.Cells[cellRowIdx, cellColIdx] = param.AsValueString();
//}
//else
//{
// if (param.AsString() != null)
// {
// worksheet.Cells[cellRowIdx, cellColIdx] = param.AsString();
// }
// else
// {
// worksheet.Cells[cellRowIdx, cellColIdx] = param.AsDouble();
// }
//}
}
else if (typeDef != null)
{
Element TypeElem = m_doc.GetElement(collection[row].GetTypeId());
var getparamLst = TypeElem.GetParameters(info.m_ParamName);
Parameter param = getparamLst.First();
if (param == null) continue;
//배경색 변경
if (param.IsReadOnly == true)
worksheet.Range[worksheet.Cells[cellRowIdx, cellColIdx], worksheet.Cells[cellRowIdx, cellColIdx]].Interior.Color = PastelRed;
else
{
if (info.IsType == true)
worksheet.Range[worksheet.Cells[cellRowIdx, cellColIdx], worksheet.Cells[cellRowIdx, cellColIdx]].Interior.Color = PastelYellow;
}
if (param.StorageType.ToString() == "Integer" || param.StorageType.ToString() == "ElementId" || param.StorageType.ToString() == "None")
worksheet.Cells[cellRowIdx, cellColIdx] = param.AsValueString();
else if (param.StorageType.ToString() == "String")
{
if(param.AsValueString()=="")
worksheet.Cells[cellRowIdx, cellColIdx] = param.AsString();
else
worksheet.Cells[cellRowIdx, cellColIdx] = param.AsValueString();
}
else if (param.StorageType.ToString() == "Double")
worksheet.Cells[cellRowIdx, cellColIdx] = Unit.FeetToMM(param.AsDouble());
//if (param.AsValueString() != null)
//{
// worksheet.Cells[cellRowIdx, cellColIdx] = param.AsValueString();
//}
//else
//{
// if (param.AsString() != null)
// {
// worksheet.Cells[cellRowIdx, cellColIdx] = param.AsString();
// }
// else
// {
// worksheet.Cells[cellRowIdx, cellColIdx] = param.AsDouble();
// }
//}
}
else
worksheet.Cells[cellRowIdx, cellColIdx] = null;
cellColIdx++;
}
}
cellColIdx = 1;
cellRowIdx++;
}
//column 검색 필터
Excel.Range rg = worksheet.Range[worksheet.Cells[1, 1], worksheet.Cells[1, 9999]];
object res = rg.AutoFilter(1);
}
//비어있는 Sheet1 삭제
foreach(Worksheet ws in workbook.Worksheets)
{
if(ws.Name == "Sheet1")
{
ws.Delete();
break;
}
}
workbook.SaveAs(saveFileDialog.FileName);
isExport = true;
if (isExport)
{
workbook.Close();
excel.Quit();
CleanProcess(new List<object> { worksheet, workbook, excel });
}
}
catch(Exception ex)
{
MessageBox.Show(ex.Message);
}
}
}
}
private void CleanProcess(List<object> items)
{
GC.Collect();
GC.WaitForPendingFinalizers();
foreach (object item in items)
{
System.Runtime.InteropServices.Marshal.ReleaseComObject(item);
}
}
}
}