Ejemplo n.º 1
0
        // (复制)另存书目记录为。注:包括下属的册、订购、期、评注记录和对象资源
        private void toolStripButton1_marcEditor_saveTo_Click(object sender, EventArgs e)
        {
            string strError = "";
            int nRet = 0;

            if (StringUtil.CompareVersion(this.MainForm.ServerVersion, "2.39") < 0)
            {
                strError = "本功能需要配合 dp2library 2.39 或以上版本才能使用";
                goto ERROR1;
            }

            string strTargetRecPath = this.m_marcEditor.Record.Fields.GetFirstSubfield("998", "t");
            if (string.IsNullOrEmpty(strTargetRecPath) == false)
            {
                DialogResult result = MessageBox.Show(this,
    "当前窗口内的记录原本是从 '" + strTargetRecPath + "' 复制过来的。是否要复制回原有位置?\r\n\r\nYes: 是; No: 否,继续进行普通复制操作; Cancel: 放弃本次操作",
    "EntityForm",
    MessageBoxButtons.YesNoCancel,
    MessageBoxIcon.Question,
    MessageBoxDefaultButton.Button1);
                if (result == System.Windows.Forms.DialogResult.Cancel)
                    return;
                if (result == System.Windows.Forms.DialogResult.Yes)
                {
                    // strTargetRecPath会发生作用
                }

                if (result == System.Windows.Forms.DialogResult.No)
                {
                    strTargetRecPath = "";
                }
            }


            bool bSaveAs = false;   // 源记录ID就是'?',追加方式。这意味着数据库中没有源记录

            // 源记录就是 ?
            if (Global.IsAppendRecPath(this.BiblioRecPath) == true)
            {
                bSaveAs = true;
            }

            MergeStyle merge_style = MergeStyle.CombinSubrecord | MergeStyle.ReserveSourceBiblio;

            BiblioSaveToDlg dlg = new BiblioSaveToDlg();
            MainForm.SetControlFont(dlg, this.Font, false);

            dlg.MainForm = this.MainForm;
            // dlg.RecPath = this.BiblioRecPath;
            if (string.IsNullOrEmpty(strTargetRecPath) == false)
                dlg.RecPath = strTargetRecPath;
            else
            {
                dlg.RecPath = this.MainForm.AppInfo.GetString(
                    "entity_form",
                    "save_to_used_path",
                    this.BiblioRecPath);
                dlg.RecID = "?";
            }

            if (bSaveAs == false)
                dlg.MessageText = "(注:本功能*可选择*是否复制书目记录下属的册、期、订购、实体记录和对象资源)\r\n\r\n将当前窗口中的书目记录 " + this.BiblioRecPath + " 复制到:";
            else
            {
                dlg.Text = "保存新书目记录到特定位置";
                dlg.MessageText = "注:\r\n1) 当前执行的是保存而不是复制操作(因为数据库里面还没有这条记录);\r\n2) 书目记录下属的册、期、订购、实体记录和对象资源会被一并保存";
                dlg.EnableCopyChildRecords = false;
            }

            if (string.IsNullOrEmpty(strTargetRecPath) == false)
                dlg.BuildLink = false;
            else
            {
                if (bSaveAs == false)
                    dlg.BuildLink = this.MainForm.AppInfo.GetBoolean(
                        "entity_form",
                        "when_save_to_build_link",
                        true);
                else
                    dlg.BuildLink = false;
            }

            if (bSaveAs == false)
                dlg.CopyChildRecords = this.MainForm.AppInfo.GetBoolean(
                    "entity_form",
                    "when_save_to_copy_child_records",
                    false);
            else
                dlg.CopyChildRecords = true;

            {
                string strMarcSyntax = this.GetCurrentMarcSyntax();
                if (string.IsNullOrEmpty(strMarcSyntax) == true)
                    strMarcSyntax = this.MarcSyntax;    // 外来数据的 MARC 格式

                dlg.MarcSyntax = strMarcSyntax;
            }

            dlg.CurrentBiblioRecPath = this.BiblioRecPath;
            this.MainForm.AppInfo.LinkFormState(dlg, "entityform_BiblioSaveToDlg_state");
            dlg.ShowDialog(this);
            // this.MainForm.AppInfo.UnlinkFormState(dlg);

            if (dlg.DialogResult != DialogResult.OK)
                return;

            if (this.BiblioRecPath == dlg.RecPath)
            {
                strError = "要保存到的位置 '" + dlg.RecPath + "' 和当前记录本来的位置 '" + this.BiblioRecPath + "' 相同,复制操作被拒绝。若确实要这样保存记录,请直接使用保存功能。";
                goto ERROR1;
            }

            if (bSaveAs == false)
            {
                this.MainForm.AppInfo.SetBoolean(
                    "entity_form",
                    "when_save_to_build_link",
                    dlg.BuildLink);
                this.MainForm.AppInfo.SetBoolean(
                    "entity_form",
                    "when_save_to_copy_child_records",
                    dlg.CopyChildRecords);
            }
            this.MainForm.AppInfo.SetString(
    "entity_form",
    "save_to_used_path",
    dlg.RecPath);

            // 源记录就是 ?
            if (bSaveAs == true)
            {
                this.BiblioRecPath = dlg.RecPath;

                // 提交所有保存请求
                // return:
                //      -1  有错。此时不排除有些信息保存成功。
                //      0   成功。
                nRet = DoSaveAll();
                if (nRet == -1)
                {
                    strError = "保存操作出错";
                    goto ERROR1;
                }

                return;
            }

            // if (dlg.CopyChildRecords == true)
            {
                // 如果当前记录没有保存,则先保存
                if (this.EntitiesChanged == true
        || this.IssuesChanged == true
        || this.BiblioChanged == true
        || this.ObjectChanged == true
        || this.OrdersChanged == true
        || this.CommentsChanged == true)
                {
                    // 警告尚未保存
                    DialogResult result = MessageBox.Show(this,
                        "当前窗口内有 " + GetCurrentChangedPartName() + " 被修改后尚未保存。复制操作前必须先保存当前记录。\r\n\r\n请问要立即保存么?",
                        "EntityForm",
                        MessageBoxButtons.OKCancel,
                        MessageBoxIcon.Question,
                        MessageBoxDefaultButton.Button2);
                    if (result == DialogResult.OK)
                    {
                        // 提交所有保存请求
                        // return:
                        //      -1  有错。此时不排除有些信息保存成功。
                        //      0   成功。
                        nRet = DoSaveAll();
                        if (nRet == -1)
                        {
                            strError = "因为保存操作出错,所以后续的复制操作被放弃";
                            goto ERROR1;
                        }
                    }
                    else
                    {
                        strError = "复制操作被放弃";
                        goto ERROR1;
                    }
                }
            }

            // 看看要另存的位置,记录是否已经存在?
            // TODO: 需要改造为合并,或者覆盖。覆盖是先删除目标位置的记录。
            if (dlg.RecID != "?")
            {
                byte[] timestamp = null;

                // 检测特定位置书目记录是否已经存在
                // parameters:
                // return:
                //      -1  error
                //      0   not found
                //      1   found
                nRet = DetectBiblioRecord(dlg.RecPath,
                    out timestamp,
                    out strError);
                if (nRet == 1)
                {
                    if (dlg.RecPath != strTargetRecPath)
                    {
#if NO
                        // 提醒覆盖?
                        DialogResult result = MessageBox.Show(this,
                            "书目记录 " + dlg.RecPath + " 已经存在。\r\n\r\n要用当前窗口中的书目记录覆盖此记录么? ",
                            "EntityForm",
                            MessageBoxButtons.YesNo,
                            MessageBoxIcon.Question,
                            MessageBoxDefaultButton.Button2);
                        if (result != DialogResult.Yes)
                            return;
#endif
                        GetMergeStyleDialog merge_dlg = new GetMergeStyleDialog();
                        MainForm.SetControlFont(merge_dlg, this.Font, false);
                        merge_dlg.SourceRecPath = this.BiblioRecPath;
                        merge_dlg.TargetRecPath = dlg.RecPath;
                        merge_dlg.MessageText = "目标书目记录 " + dlg.RecPath + " 已经存在。\r\n\r\n请指定当前窗口中的书目记录(源)和此目标记录合并的方法";

                        merge_dlg.UiState = this.MainForm.AppInfo.GetString(
        "entity_form",
        "GetMergeStyleDialog_copy_uiState",
        "");
                        merge_dlg.EnableSubRecord = dlg.CopyChildRecords;

                        this.MainForm.AppInfo.LinkFormState(merge_dlg, "entityform_GetMergeStyleDialog_copy_state");
                        merge_dlg.ShowDialog(this);
                        this.MainForm.AppInfo.UnlinkFormState(merge_dlg);
                        this.MainForm.AppInfo.SetString(
"entity_form",
"GetMergeStyleDialog_copy_uiState",
merge_dlg.UiState);

                        if (merge_dlg.DialogResult == System.Windows.Forms.DialogResult.Cancel)
                            return;

                        merge_style = merge_dlg.GetMergeStyle();

                    }

                    // this.BiblioTimestamp = timestamp;   // 为了顺利覆盖

                    // TODO: 预先检查操作者权限,确保删除书目记录和下级记录都能成功,否则就警告

#if NO
                    // 删除目标位置的书目记录,但保留其下属的实体等记录
                    nRet = DeleteBiblioRecordFromDatabase(dlg.RecPath,
                        "onlydeletebiblio",
                        timestamp,
                        out strError);
                    if (nRet == -1)
                        goto ERROR1;
#endif
                    if ((merge_style & MergeStyle.OverwriteSubrecord) != 0)
                    {
                        // 删除目标记录整个,或者删除目标位置的下级记录
                        // TODO: 测试的时候,注意不用下述调用而测试保留目标书目记录中对象的可能性
                        nRet = DeleteBiblioRecordFromDatabase(dlg.RecPath,
                            (merge_style & MergeStyle.ReserveSourceBiblio) != 0 ? "delete" : "onlydeletesubrecord",
                            timestamp,
                            out strError);
                        if (nRet == -1)
                        {
                            if ((merge_style & MergeStyle.ReserveSourceBiblio) != 0)
                                strError = "删除目标位置的书目记录 '" + dlg.RecPath + "' 时出错: " + strError;
                            else
                                strError = "删除目标位置的书目记录 '" + dlg.RecPath + "' 的全部子记录时出错: " + strError;
                            goto ERROR1;
                        }
                    }

                }
            }

            string strOutputBiblioRecPath = "";
            byte[] baOutputTimestamp = null;
            string strXml = "";

            string strOldBiblioRecPath = this.BiblioRecPath;
            string strOldMarc = this.GetMarc();    //  this.m_marcEditor.Marc;
            bool bOldChanged = this.GetMarcChanged();   //  this.m_marcEditor.Changed;

            try
            {

                // 保存原来的记录路径
                bool bOldReadOnly = this.m_marcEditor.ReadOnly;
                Field old_998 = null;
                // bool bOldChanged = this.BiblioChanged;

                if (dlg.BuildLink == true)
                {
                    nRet = this.MainForm.CheckBuildLinkCondition(
                        dlg.RecPath,    // 即将创建/保存的记录
                        strOldBiblioRecPath,    // 保存前的记录
                        false,
                        out strError);
                    if (nRet == -1 || nRet == 0)
                    {
                        // 
                        strError = "无法为记录 '" + this.BiblioRecPath + "' 建立指向 '" + strOldBiblioRecPath + "' 的目标关系:" + strError;
                        MessageBox.Show(this, strError);
                    }
                    else
                    {
                        // 保存当前记录的998字段
                        old_998 = this.m_marcEditor.Record.Fields.GetOneField("998", 0);

                        this.m_marcEditor.Record.Fields.SetFirstSubfield("998", "t", strOldBiblioRecPath);
                        /*
                        if (bOldReadOnly == false)
                            this.MarcEditor.ReadOnly = true;
                        */
                    }
                }
                else
                {
                    // 保存当前记录的998字段
                    old_998 = this.m_marcEditor.Record.Fields.GetOneField("998", 0);

                    // 清除可能存在的998$t
                    if (old_998 != null)
                    {
                        SubfieldCollection subfields = old_998.Subfields;
                        Subfield old_t = subfields["t"];
                        if (old_t != null)
                        {
                            old_998.Subfields = subfields.Remove(old_t);
                            // 如果998内一个子字段也没有了,是否这个字段要删除?
                        }
                        else
                            old_998 = null; // 表示(既然没有删除$t,就)不用恢复
                    }
                }

                string strMergeStyle = "";
                if ((merge_style & MergeStyle.ReserveSourceBiblio) != 0)
                    strMergeStyle = "reserve_source";
                else
                    strMergeStyle = "reserve_target";

                if ((merge_style & MergeStyle.MissingSourceSubrecord) != 0)
                    strMergeStyle += ",missing_source_subrecord";
                else if ((merge_style & MergeStyle.OverwriteSubrecord) != 0)
                {
                    // dp2library 尚未实现这个功能,不过本函数前面已经用 SetBiblioInfo() API 主动删除了目标位置下属的子记录,效果是一样的。(当然,这样实现起来原子性不是那么好)
                    // strMergeStyle += ",overwrite_target_subrecord";
                }

                if (dlg.CopyChildRecords == false)
                {
                    nRet = CopyBiblio(
        "onlycopybiblio",
        dlg.RecPath,
        strMergeStyle,
        out strXml,
        out strOutputBiblioRecPath,
        out baOutputTimestamp,
        out strError);
                    if (nRet == -1)
                        MessageBox.Show(this, strError);
                }
                else
                {
                    nRet = CopyBiblio(
                        "copy",
                        dlg.RecPath,
                        strMergeStyle,
                        out strXml,
                        out strOutputBiblioRecPath,
                        out baOutputTimestamp,
                        out strError);
                    if (nRet == -1)
                        MessageBox.Show(this, strError);
                }

            }
            finally
            {
#if NO
                // 复原当前窗口的记录
                if (this.m_marcEditor.Marc != strOldMarc)
                    this.m_marcEditor.Marc = strOldMarc;
                if (this.m_marcEditor.Changed != bOldChanged)
                    this.m_marcEditor.Changed = bOldChanged;
#endif
                if (this.GetMarc() /*this.m_marcEditor.Marc*/ != strOldMarc)
                {
                    // this.m_marcEditor.Marc = strOldMarc;
                    this.SetMarc(strOldMarc);
                }
                if (this.GetMarcChanged() /*this.m_marcEditor.Changed*/ != bOldChanged)
                {
                    // this.m_marcEditor.Changed = bOldChanged;
                    this.SetMarcChanged(bOldChanged);
                }
            }

            if (nRet == -1)
            {
                this.BiblioRecPath = strOldBiblioRecPath;

#if NO
                if (old_998 != null)
                {
                    // 恢复先前的998字段内容
                    for (int i = 0; i < this.MarcEditor.Record.Fields.Count; i++)
                    {
                        Field temp = this.MarcEditor.Record.Fields[i];
                        if (temp.Name == "998")
                        {
                            this.MarcEditor.Record.Fields.RemoveAt(i);
                            i--;
                        }
                    }
                    if (old_998 != null)
                    {
                        this.MarcEditor.Record.Fields.Insert(this.MarcEditor.Record.Fields.Count,
                            old_998.Name,
                            old_998.Indicator,
                            old_998.Value);
                    }
                    // 恢复操作前的ReadOnly
                    if (this.MarcEditor.ReadOnly != bOldReadOnly)
                        this.MarcEditor.ReadOnly = bOldReadOnly;

                    if (this.BiblioChanged != bOldChanged)
                        this.BiblioChanged = bOldChanged;
                }
#endif
                return;
            }

            // TODO: 询问是否要立即装载目标记录到当前窗口,还是装入新的一个种册窗,还是不装入?
            {
                DialogResult result = MessageBox.Show(this,
        "复制操作已经成功。\r\n\r\n请问是否立即将目标记录 '" + strOutputBiblioRecPath + "' 装入一个新的种册窗以便进行观察? \r\n\r\n是(Yes): 装入一个新的种册窗;\r\n否(No): 装入当前窗口;\r\n取消(Cancel): 不装入目标记录到任何窗口",
        "EntityForm",
        MessageBoxButtons.YesNoCancel,
        MessageBoxIcon.Question,
        MessageBoxDefaultButton.Button1);
                if (result == System.Windows.Forms.DialogResult.Yes)
                {
                    EntityForm form = new EntityForm();
                    form.MdiParent = this.MainForm;
                    form.MainForm = this.MainForm;
                    form.Show();
                    Debug.Assert(form != null, "");

                    form.LoadRecordOld(strOutputBiblioRecPath, "", true);
                    return;
                }
                if (result == System.Windows.Forms.DialogResult.Cancel)
                    return;
            }

            // 将目标记录装入当前窗口
            this.LoadRecordOld(strOutputBiblioRecPath, "", false);
#if NO
            // 将目标记录装入当前窗口
            this.BiblioTimestamp = baOutputTimestamp;
            this.BiblioRecPath = strOutputBiblioRecPath;


            string strBiblioDbName = Global.GetDbName(this.BiblioRecPath);

            // bool bError = false;

            // 装载新记录的entities部分

            // 接着装入相关的所有册
            string strItemDbName = this.MainForm.GetItemDbName(strBiblioDbName);
            if (String.IsNullOrEmpty(strItemDbName) == false) // 仅在当前书目库有对应的实体库时,才装入册记录
            {
                this.EnableItemsPage(true);

                nRet = this.entityControl1.LoadEntityRecords(this.BiblioRecPath,
                    out strError);
                if (nRet == -1)
                {
                    MessageBox.Show(this, strError);
                    // bError = true;
                }
            }
            else
            {
                this.EnableItemsPage(false);
                this.entityControl1.ClearEntities();
            }

            // 接着装入相关的所有期
            string strIssueDbName = this.MainForm.GetIssueDbName(strBiblioDbName);
            if (String.IsNullOrEmpty(strIssueDbName) == false) // 仅在当前书目库有对应的期库时,才装入期记录
            {
                this.EnableIssuesPage(true);
                nRet = this.issueControl1.LoadIssueRecords(this.BiblioRecPath,
                    out strError);
                if (nRet == -1)
                {
                    MessageBox.Show(this, strError);
                    // bError = true;
                }
            }
            else
            {
                this.EnableIssuesPage(false);
                this.issueControl1.ClearIssues();
            }
            // 接着装入相关的所有订购信息
            string strOrderDbName = this.MainForm.GetOrderDbName(strBiblioDbName);
            if (String.IsNullOrEmpty(strOrderDbName) == false) // 仅在当前书目库有对应的采购库时,才装入采购记录
            {
                if (String.IsNullOrEmpty(strIssueDbName) == false)
                    this.orderControl1.SeriesMode = true;
                else
                    this.orderControl1.SeriesMode = false;

                this.EnableOrdersPage(true);
                nRet = this.orderControl1.LoadOrderRecords(this.BiblioRecPath,
                    out strError);
                if (nRet == -1)
                {
                    MessageBox.Show(this, strError);
                    // bError = true;
                }
            }
            else
            {
                this.EnableOrdersPage(false);
                this.orderControl1.ClearOrders();
            }

            // 接着装入相关的所有评注信息
            string strCommentDbName = this.MainForm.GetCommentDbName(strBiblioDbName);
            if (String.IsNullOrEmpty(strCommentDbName) == false) // 仅在当前书目库有对应的评注库时,才装入评注记录
            {
                this.EnableCommentsPage(true);
                nRet = this.commentControl1.LoadCommentRecords(this.BiblioRecPath,
                    out strError);
                if (nRet == -1)
                {
                    MessageBox.Show(this, strError);
                    // bError = true;
                }
            }
            else
            {
                this.EnableCommentsPage(false);
                this.commentControl1.ClearComments();
            }

            // 接着装入对象资源
            if (dlg.CopyChildRecords == true)
            {
                nRet = this.binaryResControl1.LoadObject(this.BiblioRecPath,    // 2008/11/2 changed
                    strXml,
                    out strError);
                if (nRet == -1)
                {
                    MessageBox.Show(this, strError);
                    // bError = true;
                    // return -1;
                }
            }

            // 装载书目和<dprms:file>以外的其它XML片断
            {
                nRet = LoadXmlFragment(strXml,
                    out strError);
                if (nRet == -1)
                {
                    MessageBox.Show(this, strError);
                }
            }

            /*
            // 没有对象资源
            if (this.binaryResControl1 != null)
            {
                this.binaryResControl1.Clear();
            }
             * */

            // TODO: 装载HTML?
            Global.SetHtmlString(this.webBrowser_biblioRecord, "(空白)");   // 暂时刷新为空白
#endif

            return;
        ERROR1:
            MessageBox.Show(this, strError);
        }
Ejemplo n.º 2
0
        // 移动书目记录
        private void toolStripButton_marcEditor_moveTo_Click(object sender, EventArgs e)
        {
            string strError = "";
            int nRet = 0;

            if (StringUtil.CompareVersion(this.MainForm.ServerVersion, "2.39") < 0)
            {
                strError = "本功能需要配合 dp2library 2.39 或以上版本才能使用";
                goto ERROR1;
            }

            string strTargetRecPath = this.m_marcEditor.Record.Fields.GetFirstSubfield("998", "t");
            if (string.IsNullOrEmpty(strTargetRecPath) == false)
            {
                DialogResult result = MessageBox.Show(this,
    "当前窗口内的记录原本是从 '" + strTargetRecPath + "' 复制过来的。是否要移动回原有位置?\r\n\r\nYes: 是; No: 否,继续进行普通移动操作; Cancel: 放弃本次操作",
    "EntityForm",
    MessageBoxButtons.YesNoCancel,
    MessageBoxIcon.Question,
    MessageBoxDefaultButton.Button1);
                if (result == System.Windows.Forms.DialogResult.Cancel)
                    return;
                if (result == System.Windows.Forms.DialogResult.Yes)
                {
                    // strTargetRecPath会发生作用
                }

                if (result == System.Windows.Forms.DialogResult.No)
                {
                    strTargetRecPath = "";
                }
            }

            // 源记录就是 ?
            if (Global.IsAppendRecPath(this.BiblioRecPath) == true)
            {
                strError = "源记录尚未建立,无法执行移动操作";
                goto ERROR1;
            }

            // string strMergeStyle = "";
            MergeStyle merge_style = MergeStyle.CombinSubrecord | MergeStyle.ReserveSourceBiblio;

            BiblioSaveToDlg dlg = new BiblioSaveToDlg();
            MainForm.SetControlFont(dlg, this.Font, false);

            dlg.Text = "移动书目记录到 ...";
            dlg.MainForm = this.MainForm;
            if (string.IsNullOrEmpty(strTargetRecPath) == false)
                dlg.RecPath = strTargetRecPath;
            else
            {
                dlg.RecPath = this.MainForm.AppInfo.GetString(
                    "entity_form",
                    "move_to_used_path",
                    this.BiblioRecPath);
                dlg.RecID = "?";
            }

            dlg.MessageText = "将当前窗口中的书目记录 " + this.BiblioRecPath + " (连同下属的册、期、订购、实体记录和对象资源)移动到:";
            dlg.CopyChildRecords = true;
            dlg.EnableCopyChildRecords = false;

            dlg.BuildLink = false;

            {
                string strMarcSyntax = this.GetCurrentMarcSyntax();
                if (string.IsNullOrEmpty(strMarcSyntax) == true)
                    strMarcSyntax = this.MarcSyntax;    // 外来数据的 MARC 格式

                dlg.MarcSyntax = strMarcSyntax;
            }

            // dlg.CurrentBiblioRecPath = this.BiblioRecPath;
            this.MainForm.AppInfo.LinkFormState(dlg, "entityform_BiblioMoveToDlg_state");
            dlg.ShowDialog(this);
            // this.MainForm.AppInfo.UnlinkFormState(dlg);

            if (dlg.DialogResult != DialogResult.OK)
                return;

            if (this.BiblioRecPath == dlg.RecPath)
            {
                strError = "要移动到的位置 '" + dlg.RecPath + "' 和当前记录本来的位置 '" + this.BiblioRecPath + "' 相同,移动操作被拒绝。若确实要这样保存记录,请直接使用保存功能。";
                goto ERROR1;
            }

            this.MainForm.AppInfo.SetString(
    "entity_form",
    "move_to_used_path",
    dlg.RecPath);

            // if (dlg.CopyChildRecords == true)
            {
                // 如果当前记录没有保存,则先保存
                if (this.EntitiesChanged == true
        || this.IssuesChanged == true
        || this.BiblioChanged == true
        || this.ObjectChanged == true
        || this.OrdersChanged == true
        || this.CommentsChanged == true)
                {
                    // 警告尚未保存
                    DialogResult result = MessageBox.Show(this,
                        "当前窗口内有 " + GetCurrentChangedPartName() + " 被修改后尚未保存。移动操作前必须先保存当前记录。\r\n\r\n请问要立即保存么?",
                        "EntityForm",
                        MessageBoxButtons.OKCancel,
                        MessageBoxIcon.Question,
                        MessageBoxDefaultButton.Button2);
                    if (result == DialogResult.OK)
                    {
                        // 提交所有保存请求
                        // return:
                        //      -1  有错。此时不排除有些信息保存成功。
                        //      0   成功。
                        nRet = DoSaveAll();
                        if (nRet == -1)
                        {
                            strError = "因为保存操作出错,所以后续的移动操作被放弃";
                            goto ERROR1;
                        }
                    }
                    else
                    {
                        strError = "移动操作被放弃";
                        goto ERROR1;
                    }
                }
            }

            // 看看要另存的位置,记录是否已经存在?
            if (dlg.RecID != "?")
            {
                byte[] timestamp = null;

                // 检测特定位置书目记录是否已经存在
                // parameters:
                // return:
                //      -1  error
                //      0   not found
                //      1   found
                nRet = DetectBiblioRecord(dlg.RecPath,
                    out timestamp,
                    out strError);
                if (nRet == 1)
                {
                    //bool bOverwrite = false;
                    if (dlg.RecPath != strTargetRecPath)    // 移动回998$t情况就不询问是否覆盖了,直接选用归并方式
                    {
#if NO
                        // TODO: 用专用对话框实现
                        // 提醒覆盖?
                        DialogResult result = MessageBox.Show(this,
                            "目标书目记录 " + dlg.RecPath + " 已经存在。\r\n\r\n要用当前窗口中的书目记录(连同数字对象和下属的子记录)覆盖此记录,还是归并到此记录? \r\n\r\nYes: 覆盖; No: 归并; Cancel: 放弃本次移动操作",
                            "EntityForm",
                            MessageBoxButtons.YesNoCancel,
                            MessageBoxIcon.Question,
                            MessageBoxDefaultButton.Button2);
                        if (result == DialogResult.Cancel)
                            return;
                        if (result == System.Windows.Forms.DialogResult.Yes)
                            bOverwrite = true;
                        else
                            bOverwrite = false;
#endif
                        GetMergeStyleDialog merge_dlg = new GetMergeStyleDialog();
                        MainForm.SetControlFont(merge_dlg, this.Font, false);
                        merge_dlg.SourceRecPath = this.BiblioRecPath;
                        merge_dlg.TargetRecPath = dlg.RecPath;
                        merge_dlg.MessageText = "目标书目记录 " + dlg.RecPath + " 已经存在。\r\n\r\n请指定当前窗口中的书目记录(源)和此目标记录合并的方法";

                        merge_dlg.UiState = this.MainForm.AppInfo.GetString(
        "entity_form",
        "GetMergeStyleDialog_uiState",
        "");
                        this.MainForm.AppInfo.LinkFormState(merge_dlg, "entityform_GetMergeStyleDialog_state");
                        merge_dlg.ShowDialog(this);
                        this.MainForm.AppInfo.UnlinkFormState(merge_dlg);
                        this.MainForm.AppInfo.SetString(
"entity_form",
"GetMergeStyleDialog_uiState",
merge_dlg.UiState);

                        if (merge_dlg.DialogResult == System.Windows.Forms.DialogResult.Cancel)
                            return;

                        merge_style = merge_dlg.GetMergeStyle();
                    }

                    // this.BiblioTimestamp = timestamp;   // 为了顺利覆盖

                    // TODO: 预先检查操作者权限,确保删除书目记录和下级记录都能成功,否则就警告

#if NO
                    if (bOverwrite == true)
                    {
                        // 删除目标位置的书目记录
                        // 如果为归并模式,则保留其下属的实体等记录
                        nRet = DeleteBiblioRecordFromDatabase(dlg.RecPath,
                            bOverwrite == true ? "delete" : "onlydeletebiblio",
                            timestamp,
                            out strError);
                        if (nRet == -1)
                            goto ERROR1;
                    }
#endif
                    if ((merge_style & MergeStyle.OverwriteSubrecord) != 0)
                    {
                        // 删除目标记录整个,或者删除目标位置的下级记录
                        // TODO: 测试的时候,注意不用下述调用而测试保留目标书目记录中对象的可能性
                        nRet = DeleteBiblioRecordFromDatabase(dlg.RecPath,
                            (merge_style & MergeStyle.ReserveSourceBiblio) != 0 ? "delete" : "onlydeletesubrecord",
                            timestamp,
                            out strError);
                        if (nRet == -1)
                        {
                            if ((merge_style & MergeStyle.ReserveSourceBiblio) != 0)
                                strError = "删除目标位置的书目记录 '" + dlg.RecPath + "' 时出错: " + strError;
                            else
                                strError = "删除目标位置的书目记录 '" + dlg.RecPath + "' 的全部子记录时出错: " + strError;
                            goto ERROR1;
                        }
                    }
                }
            }

            string strOutputBiblioRecPath = "";
            byte[] baOutputTimestamp = null;
            string strXml = "";

            string strOldBiblioRecPath = this.BiblioRecPath;
            string strOldMarc = this.GetMarc(); //  this.m_marcEditor.Marc;
            bool bOldChanged = this.GetMarcChanged();   // this.m_marcEditor.Changed;

            try
            {
                // 保存原来的记录路径
                bool bOldReadOnly = this.m_marcEditor.ReadOnly;
                Field old_998 = null;

                string strDlgTargetDbName = Global.GetDbName(dlg.RecPath);
                string str998TargetDbName = Global.GetDbName(strTargetRecPath);

                // 如果移动目标和strTargetRecPath同数据库,则要去掉记录中可能存在的998$t
                if (strDlgTargetDbName == str998TargetDbName)
                {
                    // 保存当前记录的998字段
                    old_998 = this.m_marcEditor.Record.Fields.GetOneField("998", 0);

                    // 清除可能存在的998$t
                    if (old_998 != null)
                    {
                        SubfieldCollection subfields = old_998.Subfields;
                        Subfield old_t = subfields["t"];
                        if (old_t != null)
                        {
                            old_998.Subfields = subfields.Remove(old_t);
                            // 如果998内一个子字段也没有了,是否这个字段要删除?
                        }
                        else
                            old_998 = null; // 表示(既然没有删除$t,就)不用恢复
                    }
                }

                string strMergeStyle = "";
                if ((merge_style & MergeStyle.ReserveSourceBiblio) != 0)
                    strMergeStyle = "reserve_source";
                else
                    strMergeStyle = "reserve_target";

                if ((merge_style & MergeStyle.MissingSourceSubrecord) != 0)
                    strMergeStyle += ",missing_source_subrecord";
                else if ((merge_style & MergeStyle.OverwriteSubrecord) != 0)
                {
                    // dp2library 尚未实现这个功能,不过本函数前面已经用 SetBiblioInfo() API 主动删除了目标位置下属的子记录,效果是一样的。(当然,这样实现起来原子性不是那么好)
                    // strMergeStyle += ",overwrite_target_subrecord";
                }
                // combine 情况时缺省的,不用声明

                nRet = CopyBiblio(
                    "move",
                    dlg.RecPath,
                    strMergeStyle,
                    out strXml,
                    out strOutputBiblioRecPath,
                    out baOutputTimestamp,
                    out strError);
                if (nRet == -1)
                    MessageBox.Show(this, strError);

            }
            finally
            {
#if NO
                // 复原当前窗口的记录
                if (this.m_marcEditor.Marc != strOldMarc)
                    this.m_marcEditor.Marc = strOldMarc;
                if (this.m_marcEditor.Changed != bOldChanged)
                    this.m_marcEditor.Changed = bOldChanged;
#endif
                if (this.GetMarc() /*this.m_marcEditor.Marc*/ != strOldMarc)
                {
                    // this.m_marcEditor.Marc = strOldMarc;
                    this.SetMarc(strOldMarc);
                }
                if (this.GetMarcChanged() /*this.m_marcEditor.Changed*/ != bOldChanged)
                {
                    // this.m_marcEditor.Changed = bOldChanged;
                    this.SetMarcChanged(bOldChanged);
                }
            }

            if (nRet == -1)
            {
                this.BiblioRecPath = strOldBiblioRecPath;
                return;
            }

            // 将目标记录装入当前窗口
            this.LoadRecordOld(strOutputBiblioRecPath, "", false);
            return;
        ERROR1:
            MessageBox.Show(this, strError);
        }
Ejemplo n.º 3
0
        // 保存书目记录到数据库
        // parameters:
        //      bIncludeFileID  (书目记录XML)是否要根据当前rescontrol内容合成<dprms:file>元素?
        // return:
        //      -1  出错
        //      0   没有保存
        //      1   已经保存
        /// <summary>
        /// 保存书目记录到数据库
        /// </summary>
        /// <param name="channel_param">通讯通道。如果为 null,表示函数内使用自动获得的通道</param>
        /// <param name="bIncludeFileID">(书目记录XML)是否要根据当前对象控件内容合成&lt;dprms:file&gt;元素?</param>
        /// <param name="strHtml">返回新记录的 OPAC 格式内容</param>
        /// <param name="strStyle">风格。由 displaysuccess / searchdup 之一或者逗号间隔组合而成。displaysuccess 显示最后的成功消息在框架窗口的状态条; searchdup 保存成功后发送查重消息</param>
        /// <returns>
        /// <para>-1  出错</para>
        /// <para>0   没有保存</para>
        /// <para>1   已经保存</para>
        /// </returns>
        public int SaveBiblioToDatabase(
            LibraryChannel channel_param,
            bool bIncludeFileID,
            out string strHtml,
            string strStyle = "displaysuccess,searchdup")
        {
            string strError = "";
            strHtml = "";
            int nRet = 0;

            bool bDisplaySuccess = StringUtil.IsInList("displaysuccess", strStyle);
            bool bSearchDup = StringUtil.IsInList("searchdup", strStyle);

            if (this.Cataloging == false)
            {
                strError = "当前不允许编目功能,因此也不允许保存书目信息的功能";
                return -1;
            }

            // 如果刚才在删除后模式,现在取消这个模式 2007/10/15
            if (this.DeletedMode == true)
            {
                // TODO: 除了册信息,也要考虑期、采购信息
                int nEntityCount = this.entityControl1.ItemCount;

                if (nEntityCount > 0)
                {
                    DialogResult result = MessageBox.Show(this,
"如果您用本功能将刚删除的书目记录保存回数据库,那么书目记录下属的 "
+ nEntityCount.ToString()
+ " 条实体记录将不会被保存回实体库。\r\n\r\n如果要在保存书目数据的同时也完整保存这些被删除的实体记录,请先在种册窗工具条上选择“.../使能编辑保存”功能,然后再使用“全部保存”按钮"
+ "\r\n\r\n是否要在不保存实体记录的情况下单独保存书目记录? (Yes 是 / No 放弃单独保存书目记录的操作)",
"EntityForm",
MessageBoxButtons.YesNo,
MessageBoxIcon.Question,
MessageBoxDefaultButton.Button2);
                    if (result == DialogResult.No)
                    {
                        strError = "放弃保存书目记录";
                        goto ERROR1;
                    }
                }
            }

            string strTargetPath = this.BiblioRecPath;
            if (string.IsNullOrEmpty(strTargetPath) == true)
            {
                // 需要询问保存的路径
                BiblioSaveToDlg dlg = new BiblioSaveToDlg();
                MainForm.SetControlFont(dlg, this.Font, false);

                dlg.MainForm = this.MainForm;
                dlg.Text = "仅保存书目记录";
                dlg.MessageText = "请指定新书目记录要保存到的位置";
                dlg.EnableCopyChildRecords = false;

                dlg.BuildLink = false;

                dlg.CopyChildRecords = false;

                {
                    string strMarcSyntax = this.GetCurrentMarcSyntax();
                    if (string.IsNullOrEmpty(strMarcSyntax) == true)
                        strMarcSyntax = this.MarcSyntax;    // 外来数据的 MARC 格式

                    dlg.MarcSyntax = strMarcSyntax;
                }

                dlg.CurrentBiblioRecPath = this.BiblioRecPath;
                this.MainForm.AppInfo.LinkFormState(dlg, "entityform_BiblioSaveToDlg_state");
                dlg.ShowDialog(this);
                // this.MainForm.AppInfo.UnlinkFormState(dlg);

                if (dlg.DialogResult != DialogResult.OK)
                    return 0;

                strTargetPath = dlg.RecPath;
            }

            // 保存前的准备工作
            {
                // 初始化 dp2circulation_marc_autogen.cs 的 Assembly,并new DetailHost对象
                // return:
                //      -1  error
                //      0   没有重新初始化Assembly,而是直接用以前Cache的Assembly
                //      1   重新(或者首次)初始化了Assembly
                nRet = this._genData.InitialAutogenAssembly(strTargetPath,
                    out strError);
                if (nRet == -1)
                    goto ERROR1;
                if (this._genData.DetailHostObj != null)
                {
                    BeforeSaveRecordEventArgs e = new BeforeSaveRecordEventArgs();
                    // this._genData.DetailHostObj.BeforeSaveRecord(this.m_marcEditor, e);
                    this._genData.DetailHostObj.Invoke("BeforeSaveRecord", this.m_marcEditor, e);
                    if (string.IsNullOrEmpty(e.ErrorInfo) == false)
                    {
                        MessageBox.Show(this, "保存前的准备工作失败: " + e.ErrorInfo + "\r\n\r\n但保存操作仍将继续");
                    }
                }
            }

            // 获得书目记录XML格式
            string strXmlBody = "";
            nRet = this.GetBiblioXml(
                "", // 迫使从记录路径中看marc格式
                bIncludeFileID,
                out strXmlBody,
                out strError);
            if (nRet == -1)
                goto ERROR1;

            LibraryChannel channel = channel_param;
            if (channel == null)
                channel = this.MainForm.GetChannel();
            try
            {

                bool bPartialDenied = false;
                string strOutputPath = "";
                byte[] baNewTimestamp = null;
                string strWarning = "";
                nRet = SaveXmlBiblioRecordToDatabase(
                    channel,
                    strTargetPath,
                    this.DeletedMode == true,
                    strXmlBody,
                    this.BiblioTimestamp,
                    out strOutputPath,
                    out baNewTimestamp,
                    out strWarning,
                    out strError);
                if (nRet == -1)
                    goto ERROR1;
                if (string.IsNullOrEmpty(strWarning) == false)
                    MessageBox.Show(this, strWarning);
                if (channel.ErrorCode == ErrorCode.PartialDenied)
                    bPartialDenied = true;

                this.BiblioTimestamp = baNewTimestamp;
                this.BiblioRecPath = strOutputPath;
                this.BiblioOriginPath = strOutputPath;

                this.BiblioChanged = false;

                // 如果刚才在删除后模式,现在取消这个模式 2007/10/15
                if (this.DeletedMode == true)
                {
                    this.DeletedMode = false;

                    // 重新装载实体记录,以便反映其listview变空的事实
                    // 接着装入相关的所有册
                    nRet = this.entityControl1.LoadItemRecords(
                        channel,
                        this.BiblioRecPath,
                        null,
                        // this.DisplayOtherLibraryItem,
                        this.DisplayOtherLibraryItem == true ? "getotherlibraryitem" : "",
                        out strError);
                    if (nRet == -1)
                        goto ERROR1;
                }

                // 清除ReadOnly状态,如果998$t已经消失
                if (this.m_marcEditor.ReadOnly == true)
                {
                    string strTargetBiblioRecPath = this.m_marcEditor.Record.Fields.GetFirstSubfield("998", "t");
                    if (String.IsNullOrEmpty(strTargetBiblioRecPath) == true)
                        this.m_marcEditor.ReadOnly = false;
                }

                if (bDisplaySuccess == true)
                {
                    this.MainForm.StatusBarMessage = "书目记录 '" + this.BiblioRecPath + "' 保存成功";
                    // MessageBox.Show(this, "书目记录保存成功。");
                }

                if (bSearchDup == true)
                {
                    if (this.AutoSearchDup == true)
                        API.PostMessage(this.Handle, WM_SEARCH_DUP, 0, 0);
                }

                // if (bPartialDenied == true)
                {
                    // 获得实际保存的书目记录
                    string[] results = null;
                    string[] formats = null;
                    if (bPartialDenied == true)
                    {
                        formats = new string[2];
                        formats[0] = "html";
                        formats[1] = "xml";
                    }
                    else
                    {
                        formats = new string[1];
                        formats[0] = "html";
                    }
                    long lRet = channel.GetBiblioInfos(
        Progress,
        strOutputPath,
        "",
        formats,
        out results,
        out baNewTimestamp,
        out strError);
                    if (lRet == 0)
                    {
                        strError = "重新装载时,路径为 '" + strOutputPath + "' 的书目记录没有找到 ...";
                        goto ERROR1;
                    }
                    if (results == null)
                    {
                        strError = "重新装载书目记录时出错: result == null {6C619D72-73B0-48E0-8248-AB9348297D4F}";
                        goto ERROR1;
                    }

                    {
                        // 重新显示 OPAC 书目信息
                        // TODO: 需要在对象保存完以后发出这个指令
                        Debug.Assert(results.Length >= 1, "");
                        if (results.Length > 0)
                        {
                            strHtml = results[0];
#if NO
                        this.m_webExternalHost_biblio.SetHtmlString(strHtml,
                            "entityform_biblio");
#endif
                        }
                    }

                    DoViewComment(false);   // 重新显示固定面板区的属性 XML 2015/7/11

                    if (bPartialDenied == true)
                    {
                        if (results.Length < 2)
                        {
                            strError = "重新装载书目记录时出错: result.Length[" + results.Length.ToString() + "] 小于 2";
                            goto ERROR1;
                        }
                        PartialDeniedDialog dlg = new PartialDeniedDialog();

                        MainForm.SetControlFont(dlg, this.Font, false);
                        dlg.SavingXml = strXmlBody;
                        Debug.Assert(results.Length >= 2, "");
                        dlg.SavedXml = results[1];
                        dlg.MainForm = this.MainForm;

                        this.MainForm.AppInfo.LinkFormState(dlg, "PartialDeniedDialog_state");
                        dlg.ShowDialog(this);
                        this.MainForm.AppInfo.UnlinkFormState(dlg);

                        if (dlg.DialogResult == System.Windows.Forms.DialogResult.OK)
                        {
                            string strOutputBiblioRecPath = "";
                            string strXml = "";
                            string strSubRecords = "";
                            // 将实际保存的记录装入 MARC 编辑器
                            // return:
                            //      -1  error
                            //      0   not found
                            //      1   found
                            nRet = LoadBiblioRecord(
                                channel,
                                strOutputPath,
                                "",
                                false,
                                false,
                                out strOutputBiblioRecPath,
                                out strXml,
                                out strSubRecords,
                                out strError);
                            if (nRet == -1)
                            {
                                strError = "重新装载书目记录时出错: " + strError;
                                goto ERROR1;
                            }
                        }
                    }
                }
                return 1;
            }
            finally
            {
                if (channel_param == null)
                    this.MainForm.ReturnChannel(channel);
            }

        ERROR1:
            MessageBox.Show(this, strError);
            return -1;
        }
Ejemplo n.º 4
0
        // 保存到其它书目库
        // parameters:
        //      bCopy   是否为复制。如果是 false,表示移动
        // return:
        //      -1  出错
        //      0   放弃
        //      1   成功
        int CopyToAnotherDatabase(
            bool bCopy,
            out string strError)
        {
            strError = "";
            // int nRet = 0;

            string strActionName = "";
            if (bCopy)
                strActionName = "复制";
            else
                strActionName = "移动";

            // 选择目标库名,还有选定是否要将下属记录也保存过去
            // 需要询问保存的路径
            BiblioSaveToDlg dlg = new BiblioSaveToDlg();
            MainForm.SetControlFont(dlg, this.Font, false);

            dlg.MainForm = this.MainForm;
            dlg.Text = strActionName + "书目记录到数据库";

            dlg.MessageText = "请指定书目记录要追加" + strActionName + "到的位置";
            dlg.EnableCopyChildRecords = true;

            dlg.BuildLink = false;

            if (bCopy)
                dlg.CopyChildRecords = false;
            else
                dlg.CopyChildRecords = true;

            if (bCopy)
                dlg.MessageText += "\r\n\r\n(注:本功能*可选择*是否复制书目记录下属的册、期、订购、实体记录和对象资源)\r\n\r\n将选定的书目记录复制到:";
            else
            {
                dlg.MessageText += "\r\n\r\n注:\r\n1) 当前执行的是移动而不是复制操作;\r\n2) 书目记录下属的册、期、订购、实体记录和对象资源会被一并移动到目标位置";
                dlg.EnableCopyChildRecords = false;
            }
            // TODO: 要让记录ID为问号,并且不可改动

            dlg.CurrentBiblioRecPath = "";  // 源记录路径? 但是批处理情况下源记录路径并不确定阿
            this.MainForm.AppInfo.LinkFormState(dlg, "BiblioSearchform_BiblioSaveToDlg_state");
            dlg.ShowDialog(this);
            this.MainForm.AppInfo.UnlinkFormState(dlg);

            if (dlg.DialogResult != DialogResult.OK)
                return 0;

            if (Global.IsAppendRecPath(dlg.RecPath) == false)
            {
                strError = "目标记录路径 '" + dlg.RecPath + "' 不合法。必须是追加方式的路径,也就是说 ID 部分必须为问号";
                goto ERROR1;
            }
            // TODO: 如果源和目标库名相同,要警告

            string strAction = "";
            if (bCopy)
            {
                if (dlg.CopyChildRecords == false)
                    strAction = "onlycopybiblio";
                else
                    strAction = "copy";
            }
            else
            {
                if (dlg.CopyChildRecords == false)
                    strAction = "onlymovebiblio";
                else
                    strAction = "move";
            }

            LibraryChannel channel = this.GetChannel();

            stop.Style = StopStyle.EnableHalfStop;
            stop.OnStop += new StopEventHandler(this.DoStop);
            stop.Initial("正在" + strActionName + "书目记录到数据库 ...");
            stop.BeginLoop();

            this.EnableControlsInSearching(false);
            this.listView_records.Enabled = false;
            try
            {
                stop.SetProgressRange(0, this.listView_records.SelectedItems.Count);

                List<ListViewItem> moved_items = new List<ListViewItem>();
                int i = 0;
                foreach (ListViewItem item in this.listView_records.SelectedItems)
                {
                    Application.DoEvents();	// 出让界面控制权

                    if (stop != null && stop.State != 0)
                    {
                        strError = "用户中断";
                        goto ERROR1;
                    }

                    string strRecPath = ListViewUtil.GetItemText(item, 0);

                    if (string.IsNullOrEmpty(strRecPath) == true)
                        continue;

                    // 观察源记录是否有998$t ?

                    // 是否要自动创建998字段内容?

                    string strOutputBiblioRecPath = "";
                    byte[] baOutputTimestamp = null;
                    string strOutputBiblio = "";

                    stop.SetMessage("正在" + strActionName + "书目记录 '" + strRecPath + "' 到 '" + dlg.RecPath + "' ...");

                    // 2016/3/23
                    channel.Timeout = new TimeSpan(0, 40, 0);   // 复制的时候可能需要复制对象,所需时间一般很长

                REDO:
                    // result.Value:
                    //      -1  出错
                    //      0   成功,没有警告信息。
                    //      1   成功,有警告信息。警告信息在 result.ErrorInfo 中
                    long lRet = channel.CopyBiblioInfo(
                        this.stop,
                        strAction,
                        strRecPath,
                        "xml",
                        null,
                        null,    // this.BiblioTimestamp,
                        dlg.RecPath,
                        null,   // strXml,
                        "",
                        out strOutputBiblio,
                        out strOutputBiblioRecPath,
                        out baOutputTimestamp,
                        out strError);
                    if (lRet == -1)
                    {
                        DialogResult result = MessageBox.Show(this,
"复制或移动书目记录 '" + strRecPath + " --> " + dlg.RecPath + "' 时出现错误: " + strError + "。\r\n\r\n是否重试? (Yes 重试;No 跳过此条、继续后面处理;Cancel 放弃未完成的操作)",
"BiblioSearchForm",
MessageBoxButtons.YesNoCancel,
MessageBoxIcon.Question,
MessageBoxDefaultButton.Button1);
                        if (result == System.Windows.Forms.DialogResult.Yes)
                            goto REDO;
                        if (result == System.Windows.Forms.DialogResult.No)
                            goto CONTINUE;
                        goto ERROR1;
                    }

                    if (bCopy == false)
                        moved_items.Add(item);

                CONTINUE:
                    stop.SetProgressValue(++i);
                }

                foreach (ListViewItem item in moved_items)
                {
                    item.Remove();
                }
            }
            finally
            {
                stop.EndLoop();
                stop.OnStop -= new StopEventHandler(this.DoStop);
                stop.Initial("");
                stop.HideProgress();
                stop.Style = StopStyle.None;

                this.ReturnChannel(channel);

                this.EnableControlsInSearching(true);
                this.listView_records.Enabled = true;
            }

            return 1;
        ERROR1:
            // MessageBox.Show(this, strError);
            return -1;
        }