public override PersistencyHelper.SaveResult Save(bool activateOpcaoCancelar)
        {
            var preTransactionAction = new PreTransactionAction();
            var args = new PersistencyHelper.FedoraIngestPreTransactionArguments();
            preTransactionAction.args = args;
            bool ingestSuccess = true;

            if (controlObjetoDigital1.disableSave) return PersistencyHelper.SaveResult.nothingToSave;

            preTransactionAction.preTransactionDelegate = delegate(PersistencyHelper.PreTransactionArguments preTransactionArgs)
            {
                string msg = null;

                if (odHelper.currentODComp != null)
                    ingestSuccess = SessionHelper.AppConfiguration.GetCurrentAppconfiguration().FedoraHelperSingleton.Ingest(odHelper.currentODComp, out msg);
                else
                    odHelper.currentODSimples.ForEach(odSimples => ingestSuccess &= SessionHelper.AppConfiguration.GetCurrentAppconfiguration().FedoraHelperSingleton.Ingest(odSimples, out msg));

                if (ingestSuccess)
                    odHelper.newObjects.Keys.ToList().ForEach(k => { k.pid = odHelper.newObjects[k].pid; });

                preTransactionArgs.cancelAction = !ingestSuccess;
                preTransactionArgs.message = msg;
            };

            PersistencyHelper.SaveResult successfulSave = PersistencyHelper.save(preTransactionAction, activateOpcaoCancelar);

            if (successfulSave != PersistencyHelper.SaveResult.successful && !ingestSuccess)
            {
                MessageBox.Show("Ocorreu um erro na ingestão do objeto digital.", "Ingestão", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                odHelper.newObjects.Clear();
                odHelper.mContexto = ObjetoDigitalFedoraHelper.Contexto.nenhum;
                odHelper.currentODComp = null;
                odHelper.currentODSimples = null;
            }
            else if (successfulSave == PersistencyHelper.SaveResult.successful)
            {
                GISA.Search.Updater.updateNivelDocumental(odHelper.currentNivel.ID);
            }

            return successfulSave;
        }
        public static SaveResult save(PreTransactionAction preTransactionAction, preConcDelegate pcDelegate, PreConcArguments pcArguments, preSaveDelegate psDelegate, PreSaveArguments psArguments, PostSaveAction postSaveAction, bool activateOpcaoCancelar)
		{
			Concorrencia conc = new Concorrencia();
			IDbTransaction tran = null;
            SaveResult successfulSave = SaveResult.successful;
			GisaDataSetHelper.HoldOpen ho = null;
			long startTicks = 0;
			bool savedWithoutDeadlock = false;
			// Variavel que indica qual a tabela que está a ser gravada (tem o debugging como fim)
			string currentTable = string.Empty;
			DataSet gBackup = null;
			ArrayList changedRowsArrayList = null;
			// Variável que vai manter a informação das linhas "added" cujos Ids são gerados automaticamente
			// antes e depois de serem gravadas (antes de essas linhas serem gravadas os seus IDs são
			// negativos e depois são-lhe atribuidos valores positivos
			Hashtable trackNewIds = new Hashtable();

            try
            {
                if (preTransactionAction != null)
                {
                    preTransactionAction.ExecuteAction();
                    if (preTransactionAction.args.cancelAction)
                    {
                        MessageBox.Show(preTransactionAction.args.message, "Erro", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                        GisaDataSetHelper.GetInstance().RejectChanges();
                        return SaveResult.nothingToSave;
                    }
                }
            }
            catch (Exception e) { 
                Trace.WriteLine(e.ToString());
                return SaveResult.unsuccessful; }
            finally { }



			while (! savedWithoutDeadlock)
			{
				try
				{
					if (pcDelegate != null)
					{
						ho = new GisaDataSetHelper.HoldOpen(GisaDataSetHelper.GetConnection());
						tran = ho.Connection.BeginTransaction(GisaDataSetHelper.GetTransactionIsolationLevel());
						pcArguments.tran = tran;
						gBackup = new DataSet();
						gBackup.CaseSensitive = true;
						pcArguments.gisaBackup = gBackup;
						pcArguments.continueSave = true;
						pcDelegate(pcArguments);

						//no caso de se pretender apagar uma relacao hierarquica ha a possibilidade de 
						//não ser necessário prosseguir com a gravação dos dados por razoes de logica
						//(ver o delegate verifyIfCanDeleteRH)
						if (! pcArguments.continueSave)
						{
							tran.Commit();
							savedWithoutDeadlock = true;
                            successfulSave = SaveResult.unsuccessful;
                            break;
						}
					}

					//verifica logo à cabeça se houve de facto alguma alteração ao dataset
					if (! (GisaDataSetHelper.GetInstance().HasChanges()))
					{
                        return SaveResult.nothingToSave;
					}

					//obter um arraylist com estruturas que indicam para cada tabela quais as linhas que foram alteradas
					changedRowsArrayList = getCurrentDatasetChanges(conc);
					if (changedRowsArrayList == null)
					{
                        return SaveResult.nothingToSave;
					}

					while (true)
					{
						if (ho == null)
						{
							ho = new GisaDataSetHelper.HoldOpen(GisaDataSetHelper.GetConnection());
						}
						if (tran == null)
						{
							tran = ho.Connection.BeginTransaction(GisaDataSetHelper.GetTransactionIsolationLevel());
						}

						//manter 2 datasets com linhas provenientes da bd
						//isto para permitir a detecção de novos e possiveis conflitos qd o utilizador perante 1 problema de concorrencia pretende manter as suas alterações
						//a estratégia passa por verificar se houve alterações no 1º (e principal) dataset com as linhas da bd
						if (originalRowsDB1 == null)
						{
							//guardar as linhas neste dataset

							//FIXME: changedRowsArrayList esta a chegar com tabelas repetidas (!)
							originalRowsDB1 = conc.getOriginalRowsDB(changedRowsArrayList, tran);
						}
						else if (originalRowsDB1 != null && originalRowsDB2 == null)
						{
							//o dataset principal (originalRowsDB1) ja esta preenchido e o utilizador pretende manter as suas alterações

							//o dataset principal (originalRowsDB1) ja esta preenchido e o utilizador pretende manter as suas alterações
							// as linhas da BD vao parar ao 2º dataset
							originalRowsDB2 = conc.getOriginalRowsDB(changedRowsArrayList, tran);



							if (originalRowsDB2 == null)
							{
								originalRowsDB1 = null;
							}
						}
						else if (originalRowsDB1 != null && originalRowsDB2 != null)
						{
							//os 2 datasets estao preenchidos (o que quer dizer que estamos perante a 2ª situação de concorrencia consecutiva (no mínimo) na mesma mudança de contexto)

							//nesta situação o dataset principal passa a ter as alterações contidas no 2º para que neste último passem a constar os novos dados provenientes da BD
							//se não existirem novas linhas, quer dizer que as alterações feitas em memória coincidem com aquelas existentes na BD

							//verificar se existem novas linhas
							if (! (conc.getOriginalRowsDB(changedRowsArrayList, tran) == null))
							{
								originalRowsDB1 = originalRowsDB2.Copy();
								originalRowsDB2 = conc.getOriginalRowsDB(changedRowsArrayList, tran);
							}
							else
							{
								originalRowsDB1 = null;
								originalRowsDB2 = null;
							}
						}

						//se não existirem conflitos de concorrencia
						if (! ((originalRowsDB1 != null && originalRowsDB2 == null && conc.temLinhas(originalRowsDB1)) || (originalRowsDB1 != null && originalRowsDB2 != null && conc.wasModified(originalRowsDB1, originalRowsDB2, changedRowsArrayList))))
						{
							//não há concorrência quando o originalRowsDB1 não tem linhas e originalRowsDB2 está vazio ou quando os dois datasets são diferentes

							break;
						}
						else
						{
							//caso existam conflitos, é apresentado ao utilizador uma mensagem a indicar os pontos de conflito e de que forma os pretende resolver


							//ToDo: verificar a necessidade de fazer rollback
							tran.Rollback();
							ho.Dispose();
							ho = null;
							tran = null;

							frm.DetalhesUser = Concorrencia.StrConcorrenciaUser.ToString();
							frm.DetalhesBD = Concorrencia.StrConcorrenciaBD.ToString();
							frm.btnCancel.Enabled = activateOpcaoCancelar;

							switch (frm.ShowDialog())
							{
								case DialogResult.Yes:
									//mantem-se dentro do ciclo de forma a voltar a verificar se existe concorrencia ou nao
									//ao mesmo tempo que este tratamento de conflitos e executado outro utilizador pode já ter feito novas alterações                           

									//é necessario limpar as variaveis que mantem as mensagens sobre a concorrencia para o caso de neste situação ainda existirem novos situações de conflito
									Concorrencia.StrConcorrenciaBD.Remove(0, Concorrencia.StrConcorrenciaBD.Length);
									Concorrencia.StrConcorrenciaUser.Remove(0, Concorrencia.StrConcorrenciaUser.Length);

									break;
								case DialogResult.No:
									//gravar em memoria as linhas obtidas da base de dados e sai do metodo
									if (originalRowsDB2 != null)
									{
										//se no dataset originalRowsDB2 existirem linhas, logo é este que vai ser gravado
										conc.MergeDatasets(originalRowsDB2, GisaDataSetHelper.GetInstance(), DataSetTablesOrderedA);
									}
									else
									{
                                        conc.MergeDatasets(originalRowsDB1, GisaDataSetHelper.GetInstance(), DataSetTablesOrderedA);
									}
									conc.ClearRowsChangedToModified();
									cleanConcurrencyVariables();

									return successfulSave;
								case DialogResult.Cancel:
									cleanConcurrencyVariables();

                                    successfulSave = SaveResult.cancel;
									return successfulSave;
							}
						}
					}

					startTicks = DateTime.Now.Ticks;

					if (Concorrencia.StrConcorrenciaLinhasNaoGravadas.Length > 0)
					{
						MessageBox.Show("A informação referente aos campos seguintes não pode ser gravada " + Environment.NewLine + "por ter sido, entretanto, eliminada: " + System.Environment.NewLine + Concorrencia.StrConcorrenciaLinhasNaoGravadas.ToString(), "Gravação de dados.");
					}

					// Chamar qualquer tarefa de "pré-gravação" que possa ter sido definida
					if (psDelegate != null)
					{
						psArguments.tran = tran;
						psDelegate(psArguments);
					}

					// forma de manter a informação referente à actualização dos Ids das linhas quando 
					// estas são adicionadas na base de dados, isto é, saber qual o valor (negativo) 
					// do ID antes da linha ser gravada e o valor (positivo) atribuído pela base de dados
					// depois do save
					trackNewIds.Clear();
					conc.startTrackingIdsAddedRows(GisaDataSetHelper.GetInstance(), changedRowsArrayList, ref trackNewIds);

					// garantir que filhos das linhas a eliminar que não estão carregados ficam também eles eliminados
					//ToDo: em getChildRowsFromDB utilizar dataset de trabalho para obter as relações entre tabelas. Passar ao metodo o origRowsDB para que as linhas obtidas lhe sejam directamente adicionadas
					ArrayList rows = new ArrayList();
					ArrayList afectedTables = new ArrayList();
					GisaDataSetHelper.ManageDatasetConstraints(false);
					foreach (Concorrencia.changedRows changedRow in changedRowsArrayList)
					{
						currentTable = changedRow.tab;
						if (changedRow.rowsDel.Count > 0)
						{
							cascadeManageChildDeletedRows(changedRow.tab, changedRow.rowsDel, conc, tran);
						}

						// alterar o estado das Rowstate.Deleted para Rowstate.Unchanged e passa-las a isDeleted=True
						DataRow delRow = null;

						if (changedRow.rowsDel.Count > 0)
						{

							while (changedRow.rowsDel.Count > 0)
							{
                                if (changedRow.tab.Equals("ControloAutDataDeDescricao") || changedRow.tab.Equals("FRDBaseDataDeDescricao"))
                                {
                                    delRow = (DataRow)(changedRow.rowsDel[0]);
                                    delRow.RejectChanges();
                                    changedRow.rowsDel.RemoveAt(0);
                                }
                                else
                                {
                                    delRow = (DataRow)(changedRow.rowsDel[0]);
                                    delRow.RejectChanges();
                                    delRow["isDeleted"] = 1;
                                    changedRow.rowsMod.Add(delRow);
                                    changedRow.rowsDel.RemoveAt(0);
                                }
							}
						}

						rows.Clear();
						rows.AddRange(changedRow.rowsAdd);
						rows.AddRange(changedRow.rowsMod);
						PersistencyHelperRule.Current.saveRows(GisaDataSetHelper.GetInstance().Tables[changedRow.tab], (DataRow[])(rows.ToArray(typeof(DataRow))), tran);
					}

                    if (postSaveAction != null)
                    {
                        postSaveAction.args.tran = tran;
                        postSaveAction.ExecuteAction();
                    }

					conc.ClearRowsChangedToModified();
					GisaDataSetHelper.ManageDatasetConstraints(true);
					tran.Commit();
					savedWithoutDeadlock = true;
					Debug.WriteLine("Save: " + new TimeSpan(DateTime.Now.Ticks - startTicks).ToString());
					Trace.WriteLine("Save completed.");
				}
				catch (Exception ex)
				{
                    Trace.WriteLine(ex);

					//GisaDataSetHelper.GetInstance().RejectChanges()
					if (DBAbstractDataLayer.DataAccessRules.ExceptionHelper.isDeadlockException(ex))
					{
						Trace.WriteLine(">>> Deadlock (save).");
						conc.prepareRollBackDataSet(ref trackNewIds);
						tran.Rollback();
						tran = null;
						if (conc.mGisaBackup != null && gBackup != null)
						{
                            conc.MergeDatasets(gBackup, conc.gisabackup, DataSetTablesOrderedA);
						}
						if (conc.mGisaBackup != null)
						{
                            conc.MergeDatasets(conc.mGisaBackup, GisaDataSetHelper.GetInstance(), DataSetTablesOrderedA, trackNewIds);
						}
						conc.deleteUnusedRows(GisaDataSetHelper.GetInstance(), ref trackNewIds);
						gBackup = null;
					}
					else if (DBAbstractDataLayer.DataAccessRules.ExceptionHelper.isTimeoutException(ex))
					{
						Trace.WriteLine(">>> Timeout (save).");
						conc.prepareRollBackDataSet(ref trackNewIds);
						tran = null;
						if (conc.mGisaBackup != null && gBackup != null)
						{
                            conc.MergeDatasets(gBackup, conc.gisabackup, DataSetTablesOrderedA);
						}
						if (conc.mGisaBackup != null)
						{
                            conc.MergeDatasets(conc.mGisaBackup, GisaDataSetHelper.GetInstance(), DataSetTablesOrderedA, trackNewIds);
						}
						conc.deleteUnusedRows(GisaDataSetHelper.GetInstance(), ref trackNewIds);
						gBackup = null;
					}
					else
					{
	#if DEBUG
						Trace.WriteLine(currentTable);
	#endif
						Trace.WriteLine("Save failed.");
						Trace.WriteLine(ex);
						Debug.Assert(false, "Save failed.");

						if (tran != null)
						{
							tran.Rollback();
						}
						tran = null;

						MessageBox.Show("Ocorreu um erro inesperado durante a gravação " + Environment.NewLine + "da informação e por esse motivo a aplicação irá " + Environment.NewLine + "fechar. Por favor contacte o administrador do sistema", "Erro", MessageBoxButtons.OK, MessageBoxIcon.Error);
                        throw;
					}
				}
				finally
				{
					if (tran != null)
					{
						tran.Dispose();
					}

					cleanConcurrencyVariables();

					if (savedWithoutDeadlock)
					{
						conc.mGisaBackup = null;
					}

					if (ho != null)
					{
						ho.Dispose();
						ho = null;
					}
				}
			}


			return successfulSave;
		}
        private void RemoveNivel()
        {
            GISATreeNode node = null;
            GISATreeNode parentNode = null;
            GISADataset.NivelRow nUpperRow = null;
            GISADataset.RelacaoHierarquicaRow rhRow = null;
            GISADataset.NivelRow nRow = null;
            var objDigital = default(ObjDigital);
            if (this.nivelNavigator1.PanelToggleState == NivelNavigator.ToggleState.Estrutural)
            {
                if (this.nivelNavigator1.SelectedNode != null)
                {
                    nRow = ((GISATreeNode)this.nivelNavigator1.SelectedNode).NivelRow;
                    rhRow = ((GISATreeNode)this.nivelNavigator1.SelectedNode).RelacaoHierarquicaRow;
                }
                node = (GISATreeNode)this.nivelNavigator1.SelectedNode;
                parentNode = (GISATreeNode)node.Parent;
                nUpperRow = (GISADataset.NivelRow)node.NivelUpperRow;
            }
            else
            {
                nRow = this.nivelNavigator1.SelectedNivel;
                // Verificar se a relacção hierárquica ainda é a mesma apresentada na interface (se o
                // utilizador estiver a ver a lista que contem o nível a apagar e entretanto outro utilizador
                // o ter colocado noutro ponto da árvore, a relação hierárquica presente em memória deixa
                // de corresponder com aquela que é apresentada na interface quando esse nível é selecionado;
                // quando o nível é selecionado a informação no DataSet de trabalho é actualizado mas não
                // actualiza a interface)
                if (GisaDataSetHelper.GetInstance().RelacaoHierarquica.Select(string.Format("ID={0} AND IDUpper={1}", nRow.ID, this.nivelNavigator1.ContextBreadCrumbsPathID)).Length > 0)
                    rhRow = (GISADataset.RelacaoHierarquicaRow)(GisaDataSetHelper.GetInstance().RelacaoHierarquica.Select(string.Format("ID={0} AND IDUpper={1}", nRow.ID, this.nivelNavigator1.ContextBreadCrumbsPathID))[0]);
                else
                {
                    MessageBox.Show("Esta operação não pode ser concluída pelo facto de a localização na estrutura " + System.Environment.NewLine + "do nível selecionado ter sido alterada por outro utilizador.", "Eliminar Nível", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                    return;
                }
                nUpperRow = (GISADataset.NivelRow)(GisaDataSetHelper.GetInstance().Nivel.Select(string.Format("ID={0}", this.nivelNavigator1.ContextBreadCrumbsPathID))[0]);

                if (!FedoraHelper.CanDeleteODsAssociated2UI(nRow, out objDigital))
                    return;
            }

            // Não permitir a eliminação de relações entre EPs
            if (TipoNivel.isNivelOrganico(nRow) && TipoNivel.isNivelOrganico(nUpperRow))
            {
                MessageBox.Show("A alteração de relações entre entidades produtoras deverão ser efectuadas através do controlo de autoridade.", "Eliminação de relação", MessageBoxButtons.OK, MessageBoxIcon.Information);
                return;
            }

            var assocODs = FedoraHelper.GetAssociatedODsDetailsMsg(nRow.ID);
            if (assocODs.Length > 0)
            {
                FormDeletionReport form = new FormDeletionReport();
                form.Text = "Eliminação de unidade de informação";
                form.Interrogacao = "A unidade de informação selecionada tem objeto(s) digital(ais) associado(s). " + System.Environment.NewLine +
                        "Se eliminar esta unidade de informação, os objeto(s) digital(ais) " + System.Environment.NewLine + " também serão eliminado(s)." + System.Environment.NewLine +
                        "Pretende continuar?";
                form.Detalhes = assocODs;

                if (form.ShowDialog() == DialogResult.Cancel) return;
            }
            else if (MessageBox.Show("Tem a certeza que deseja eliminar o nível selecionado?", "Eliminação de relação", MessageBoxButtons.OKCancel, MessageBoxIcon.Question) == DialogResult.Cancel)
                return;

            Trace.WriteLine("A apagar nível...");

            // actualizar objecto digital caso exista
            var preTransactionAction = new PreTransactionAction();
            var fedArgs = new PersistencyHelper.FedoraIngestPreTransactionArguments();
            preTransactionAction.args = fedArgs;

            preTransactionAction.preTransactionDelegate = delegate(PersistencyHelper.PreTransactionArguments preTransactionArgs)
            {
                bool ingestSuccess = true;
                string msg = null;

                var odsToIngest = FedoraHelper.DeleteObjDigital(nRow);
                odsToIngest.ForEach(od => ingestSuccess &= SessionHelper.AppConfiguration.GetCurrentAppconfiguration().FedoraHelperSingleton.Ingest(od, out msg));

                preTransactionArgs.cancelAction = !ingestSuccess;
                preTransactionArgs.message = msg;

            };

            // Se se tratar da relação entre um nível orgânico e uma ED ou GA 
            // ou se se tratar da relação entre um nível documental e um nível 
            // orgânio é necessário proceder de outras formas
            if (TipoNivel.isNivelOrganico(nRow) && TipoNivel.isNivelLogico(nUpperRow))
            {
                if (MessageBox.Show(
                    "Por favor tenha em atenção que a entidade produtora propriamente " + System.Environment.NewLine +
                    "dita não será eliminada, apenas a relação ao nível superior o será.", "Eliminação de relação", MessageBoxButtons.OKCancel, MessageBoxIcon.Warning) == DialogResult.Cancel)
                    return;

                ((frmMain)TopLevelControl).EnterWaitMode();

                string key = ControloNivelList.getKey(node);
                PersistencyHelper.canDeleteRHRowPreConcArguments args = new PersistencyHelper.canDeleteRHRowPreConcArguments();
                args.nRowID = node.NivelRow.ID;
                args.nUpperRowID = node.NivelUpperRow.ID;
                args.rhRowID = node.RelacaoHierarquicaRow.ID;
                args.rhRowIDUpper = node.RelacaoHierarquicaRow.IDUpper;
                CurrentContext.RaiseRegisterModificationEvent(nRow.GetFRDBaseRows()[0]);
                var successfulSave = PersistencyHelper.save(DelegatesHelper.verifyIfCanDeleteRH, args);
                //tds.Add(GisaDataSetHelper.GetInstance().Tables["RelacaoHierarquica"]);
                PersistencyHelper.cleanDeletedData(PersistencyHelper.determinaNuvem("RelacaoHierarquica"));
                if (args.deleteSuccessful)
                {
                    GISA.Search.Updater.updateProdutor(node.NivelRow.GetNivelControloAutRows()[0].IDControloAut);

                    //Prevenir o beforeNewSelection que o Remove ia desencadear.
                    this.nivelNavigator1.AddHandlers();
                    this.nivelNavigator1.RemoveFromTreeview(node, key);
                    this.nivelNavigator1.RemoveHandlers();
                }
                else
                    MessageBox.Show(args.message, "Eliminação de relação", MessageBoxButtons.OK, MessageBoxIcon.Information);

                ((frmMain)TopLevelControl).LeaveWaitMode();
            }
            else if (TipoNivel.isNivelDocumental(nRow) && TipoNivel.isNivelOrganico(nUpperRow))
            {
                // Verificar que existem várias relações hierárquicas deste 
                // nível documental a entidades produtoras superiores. Nesse 
                // caso deverá ser removida a relação, caso contrário, se não 
                // existirem subníveis documentais, será eliminado o próprio 
                // nível(documental)
                int numRHs = nRow.GetRelacaoHierarquicaRowsByNivelRelacaoHierarquica().Length;
                if (numRHs > 1)
                {
                    if (MessageBox.Show(
                        "Por favor tenha em atenção que são vários os produtores deste " + System.Environment.NewLine +
                        "nível documental. O nível documental propriamente dito não " + System.Environment.NewLine +
                        "será eliminado, apenas a sua relação ao nível orgânico " + System.Environment.NewLine +
                        "superior o será.", "Eliminação de relação", MessageBoxButtons.OKCancel, MessageBoxIcon.Warning) == DialogResult.Cancel)
                        return;

                    ((frmMain)TopLevelControl).EnterWaitMode();

                    CurrentContext.RaiseRegisterModificationEvent(nRow.GetFRDBaseRows()[0]);

                    PersistencyHelper.canDeleteRHRowPreConcArguments args = new PersistencyHelper.canDeleteRHRowPreConcArguments();
                    args.nRowID = nRow.ID;
                    args.nUpperRowID = nUpperRow.ID;
                    args.rhRowID = rhRow.ID;
                    args.rhRowIDUpper = rhRow.IDUpper;
                    PersistencyHelper.SaveResult successfulSave = PersistencyHelper.save(DelegatesHelper.verifyIfCanDeleteRH, args);
                    PersistencyHelper.cleanDeletedData(PersistencyHelper.determinaNuvem("RelacaoHierarquica"));
                    if (args.deleteSuccessful)
                    {
                        if (successfulSave == PersistencyHelper.SaveResult.successful)
                        {
                            List<string> IDNiveis = new List<string>();
                            IDNiveis.Add(args.nRowID.ToString());
                            GISA.Search.Updater.updateNivelDocumental(IDNiveis);
                            GISA.Search.Updater.updateNivelDocumentalComProdutores(nRow.ID);

                            this.nivelNavigator1.RemoveSelectedLVItem();
                        }
                    }
                    else
                        MessageBox.Show(args.message, "Eliminação de relação", MessageBoxButtons.OK, MessageBoxIcon.Information);

                    ((frmMain)TopLevelControl).LeaveWaitMode();
                }
                else if (numRHs == 1)
                {
                    // Verificar que não existem subníveis documentais
                    int numSubRHs = GisaDataSetHelper.GetInstance().RelacaoHierarquica.Select(string.Format("IDUpper={0}", nRow.ID)).Length;
                    if (numSubRHs > 0)
                    {
                        MessageBox.Show("Só é possível eliminar os níveis que não tenham outros directamente associados", "Eliminação de relação", MessageBoxButtons.OK, MessageBoxIcon.Information);
                        return;
                    }
                    else
                    {
                        if (MessageBox.Show(
                            "Por favor tenha em atenção que este nível documental é produzido" + System.Environment.NewLine +
                            "por apenas uma entidade. Ao remover esta relação será perdida " + System.Environment.NewLine +
                            "não só a relação como o nível documental propriamente dito.", "Eliminação de relação", MessageBoxButtons.OKCancel, MessageBoxIcon.Warning) == DialogResult.Cancel)
                            return;

                        ((frmMain)TopLevelControl).EnterWaitMode();

                        CurrentContext.RaiseRegisterModificationEvent(nRow.GetFRDBaseRows()[0]);

                        PersistencyHelper.canDeleteRHRowPreConcArguments argsPca = new PersistencyHelper.canDeleteRHRowPreConcArguments();
                        argsPca.nRowID = nRow.ID;
                        argsPca.nUpperRowID = nUpperRow.ID;
                        argsPca.rhRowID = 0;
                        argsPca.rhRowIDUpper = 0;
                        PersistencyHelper.DeleteIDXPreSaveArguments argsPsa = new PersistencyHelper.DeleteIDXPreSaveArguments();
                        argsPsa.ID = nRow.ID;
                        PersistencyHelper.SaveResult successfulSave = PersistencyHelper.save(DelegatesHelper.verifyIfCanDeleteRH, argsPca, Nivel.DeleteNivelXInDataBase, argsPsa, preTransactionAction);
                        if (argsPca.deleteSuccessful)
                        {
                            if (successfulSave == PersistencyHelper.SaveResult.successful)
                            {
                                List<string> IDNiveis = new List<string>();
                                IDNiveis.Add(nRow.ID.ToString());
                                GISA.Search.Updater.updateNivelDocumental(IDNiveis);
                                GISA.Search.Updater.updateNivelDocumentalComProdutores(nRow.ID);

                                this.nivelNavigator1.RemoveSelectedLVItem();
                            }
                        }
                        else
                        {
                            // se o nível a eliminar se tratar de uma série ou documento solto mas que 
                            // por motivos de conflito de concorrência não foi possível executar, 
                            // o refrescamento dos botões é feito tendo como o contexto o próprio
                            // nível que se pretendeu eliminar para desta forma o estado dos mesmos
                            // estar correcta (caso contrário o estado dos botões referir-se-ia a 
                            // não haver qualquer item selecionado
                            MessageBox.Show(argsPca.message, "Eliminação de relação", MessageBoxButtons.OK, MessageBoxIcon.Information);
                            UpdateToolBarButtons(this.nivelNavigator1.SelectedItems[0]);
                        }
                        PersistencyHelper.cleanDeletedData(new List<TableDepthOrdered.TableCloudType>(new TableDepthOrdered.TableCloudType[] { PersistencyHelper.determinaNuvem("RelacaoHierarquica"), PersistencyHelper.determinaNuvem("FRDBase") }));

                        ((frmMain)TopLevelControl).LeaveWaitMode();
                    }
                }
                else
                    Debug.Assert(false, "Should never happen. There must be a relation with an upper Nivel.");
            }
            else
            {
                // Entre todos os outros tipos de nível proceder normalmente
                if (this.nivelNavigator1.PanelToggleState == NivelNavigator.ToggleState.Estrutural)
                {
                    ((frmMain)TopLevelControl).EnterWaitMode();

                    string key = ControloNivelList.getKey(node);
                    PersistencyHelper.canDeleteRHRowPreConcArguments argsPca = new PersistencyHelper.canDeleteRHRowPreConcArguments();
                    argsPca.nRowID = node.NivelRow.ID;
                    //se não se tratar de uma entidade detentora nem de um grupo de arquivos não é necessário criar uma entrada na tabela de controlo de descrição
                    if (node.NivelUpperRow != null && node.NivelRow.IDTipoNivel != TipoNivel.LOGICO)
                    {
                        argsPca.nUpperRowID = node.NivelUpperRow.ID;
                        CurrentContext.RaiseRegisterModificationEvent(nRow.GetFRDBaseRows()[0]);
                    }
                    else
                        argsPca.nUpperRowID = 0;

                    argsPca.rhRowID = 0;
                    argsPca.rhRowIDUpper = 0;
                    PersistencyHelper.DeleteIDXPreSaveArguments argsPsa = new PersistencyHelper.DeleteIDXPreSaveArguments();
                    argsPsa.ID = nRow.ID;
                    PersistencyHelper.save(DelegatesHelper.verifyIfCanDeleteRH, argsPca, Nivel.DeleteNivelXInDataBase, argsPsa);
                    PersistencyHelper.cleanDeletedData(new List<TableDepthOrdered.TableCloudType>(new TableDepthOrdered.TableCloudType[] { PersistencyHelper.determinaNuvem("RelacaoHierarquica"), PersistencyHelper.determinaNuvem("FRDBase") }));
                    if (argsPca.deleteSuccessful)
                        this.nivelNavigator1.RemoveFromTreeview(node, key);
                    else
                        MessageBox.Show(argsPca.message, "Eliminação de relação", MessageBoxButtons.OK, MessageBoxIcon.Information);

                    ((frmMain)TopLevelControl).LeaveWaitMode();
                }
                else
                {
                    if ((nRow.GetRelacaoHierarquicaRowsByNivelRelacaoHierarquica()[0].IDTipoNivelRelacionado == TipoNivelRelacionado.D ||
                        nRow.GetRelacaoHierarquicaRowsByNivelRelacaoHierarquica()[0].IDTipoNivelRelacionado == TipoNivelRelacionado.SD) &&
                        NiveisHelper.NivelFoiMovimentado(nRow.ID))
                    {
                        if (MessageBox.Show(
                                "Por favor tenha em atenção que este nível documental já foi " + System.Environment.NewLine +
                                "requisitado/devolvido. Ao remover nível documental serão perdidos " + System.Environment.NewLine +
                                "todos os seus registos referentes a requisições e devoluções.", "Eliminação de nível documental", MessageBoxButtons.OKCancel, MessageBoxIcon.Warning) == DialogResult.Cancel)
                            return;
                    }

                    ((frmMain)TopLevelControl).EnterWaitMode();

                    CurrentContext.RaiseRegisterModificationEvent(nRow.GetFRDBaseRows()[0]);

                    PersistencyHelper.canDeleteRHRowPreConcArguments argsPca = new PersistencyHelper.canDeleteRHRowPreConcArguments();
                    argsPca.nRowID = nRow.ID;
                    argsPca.nUpperRowID = nUpperRow.ID;
                    argsPca.rhRowID = 0;
                    argsPca.rhRowIDUpper = 0;
                    PersistencyHelper.DeleteIDXPreSaveArguments argsPsa = new PersistencyHelper.DeleteIDXPreSaveArguments();
                    argsPsa.ID = nRow.ID;
                    PersistencyHelper.SaveResult successfulSave = PersistencyHelper.save(DelegatesHelper.verifyIfCanDeleteRH, argsPca, Nivel.DeleteNivelXInDataBase, argsPsa, preTransactionAction);
                    PersistencyHelper.cleanDeletedData(new List<TableDepthOrdered.TableCloudType>(new TableDepthOrdered.TableCloudType[] { PersistencyHelper.determinaNuvem("RelacaoHierarquica"), PersistencyHelper.determinaNuvem("FRDBase"), PersistencyHelper.determinaNuvem("ObjetoDigital") }));
                    if (argsPca.deleteSuccessful)
                    {
                        if (successfulSave == PersistencyHelper.SaveResult.successful)
                        {
                            List<string> IDNiveis = new List<string>();
                            IDNiveis.Add(argsPsa.ID.ToString());
                            GISA.Search.Updater.updateNivelDocumental(IDNiveis);
                            if (nRow.RowState == DataRowState.Detached)
                                GISA.Search.Updater.updateNivelDocumentalComProdutores(argsPsa.ID);
                            else
                                GISA.Search.Updater.updateNivelDocumentalComProdutores(nRow.ID);

                            this.nivelNavigator1.RemoveSelectedLVItem();
                        }
                    }
                    else
                        MessageBox.Show(argsPca.message, "Eliminação de relação", MessageBoxButtons.OK, MessageBoxIcon.Information);

                    ((frmMain)TopLevelControl).LeaveWaitMode();
                }
            }

            RevalidateClipboardNivelItem();

            if (this.nivelNavigator1.PanelToggleState == NivelNavigator.ToggleState.Estrutural && parentNode != null)
            {
                //remover o nó do controlo embora sem refrescar a interface
                this.nivelNavigator1.SelectParentNode(parentNode);
                UpdateContext();
            }
            else
            {
                //A selecção foi limpa aquando da eliminação do item
                UpdateToolBarButtons();
            }
        }
 public static SaveResult save(PreTransactionAction preTransactionAction, preConcDelegate pcDelegate, PreConcArguments pcArguments, PostSaveAction postSaveAction, bool activateOpcaoCancelar)
 {
     return save(preTransactionAction, pcDelegate, pcArguments, null, null, postSaveAction, activateOpcaoCancelar);
 }
 public static SaveResult save(preConcDelegate pcDelegate, PreConcArguments pcArguments, preSaveDelegate psDelegate, PreSaveArguments psArguments, PreTransactionAction preTransactionAction)
 {
     return save(preTransactionAction, pcDelegate, pcArguments, psDelegate, psArguments, null, false);
 }
 public static SaveResult save(preSaveDelegate psDelegate, PreSaveArguments psArguments, PostSaveAction postSaveAction, PreTransactionAction preTransactionAction, bool activateOpcaoCancelar)
 {
     return save(preTransactionAction, null, null, psDelegate, psArguments, postSaveAction, activateOpcaoCancelar);
 }
 public static SaveResult save(PreTransactionAction preTransactionAction, bool activateOpcaoCancelar)
 {
     return save(preTransactionAction, null, null, null, null, null, activateOpcaoCancelar);
 }
Exemple #8
0
        public override PersistencyHelper.SaveResult Save(bool activateOpcaoCancelar)
		{
			if (this.CurrentFRDBase == null)
                return PersistencyHelper.SaveResult.unsuccessful;

            List<long> IDs = new List<long>();
            List<string> idsToUpdate = new List<string>();
			List<NivelRule.PublicacaoDocumentos> DocsID = new List<NivelRule.PublicacaoDocumentos> ();
			GISADataset.RelacaoHierarquicaRow rhRow = null;
            PersistencyHelper.SaveResult successfulSave = PersistencyHelper.SaveResult.unsuccessful;

			if ((CurrentFRDBase.NivelRow.GetRelacaoHierarquicaRowsByNivelRelacaoHierarquica().Length > 0))
			{
				rhRow = CurrentFRDBase.NivelRow.GetRelacaoHierarquicaRowsByNivelRelacaoHierarquica()[0];

				PersistencyHelper.PublishSubDocumentosPreSaveArguments psArgs1 = new PersistencyHelper.PublishSubDocumentosPreSaveArguments();
				PersistencyHelper.AvaliaDocumentosTabelaPreSaveArguments psArgs2 = new PersistencyHelper.AvaliaDocumentosTabelaPreSaveArguments();

                // publicação de subdocumentos baseado na publicação dos documentos respectivos
				if (rhRow.IDTipoNivelRelacionado == TipoNivelRelacionado.D)
				{
					//contexto é um documento
                    if (CurrentFRDBase.GetSFRDAvaliacaoRows().Length > 0)
                    {
                        GISADataset.SFRDAvaliacaoRow relRow = CurrentFRDBase.GetSFRDAvaliacaoRows()[0];

                        if ((relRow.RowState == DataRowState.Added && relRow.Publicar) || relRow.RowState == DataRowState.Modified)
                        {
                            DocsID.Add(new DBAbstractDataLayer.DataAccessRules.NivelRule.PublicacaoDocumentos(CurrentFRDBase.NivelRow.ID, CurrentFRDBase.GetSFRDAvaliacaoRows()[0].Publicar));
                            IDs.Add(CurrentFRDBase.NivelRow.ID);
                            PermissoesHelper.ChangeDocPermissionPublicados(CurrentFRDBase.NivelRow.ID, (CurrentFRDBase.GetSFRDAvaliacaoRows())[0].Publicar);
                        }
                    }
				}
                else if (rhRow.IDTipoNivelRelacionado == TipoNivelRelacionado.SR || rhRow.IDTipoNivelRelacionado == TipoNivelRelacionado.SSR)
                {
                    //o contexto é uma série ou subsérie e é alterado o estado de publicação de vários documentos simultaneamente
                    foreach (GISADataset.SFRDAvaliacaoRow sfrdAv in GisaDataSetHelper.GetInstance().SFRDAvaliacao.Select("", "", DataViewRowState.Added | DataViewRowState.ModifiedCurrent))
                    {
                        if (sfrdAv.FRDBaseRow.ID != CurrentFRDBase.ID)
                        {
                            DocsID.Add(new DBAbstractDataLayer.DataAccessRules.NivelRule.PublicacaoDocumentos(sfrdAv.FRDBaseRow.NivelRow.ID, sfrdAv.Publicar));
                            IDs.Add(sfrdAv.FRDBaseRow.NivelRow.ID);
                            PermissoesHelper.ChangeDocPermissionPublicados(sfrdAv.FRDBaseRow.NivelRow.ID, sfrdAv.Publicar);
                        }
                        else
                            IDs.Add(sfrdAv.FRDBaseRow.IDNivel);
                    }

                    if (!(CurrentFRDBase.GetSFRDAvaliacaoRows().Length == 0 || CurrentFRDBase.GetSFRDAvaliacaoRows()[0].IsIDModeloAvaliacaoNull() || (!(CurrentFRDBase.GetSFRDAvaliacaoRows()[0].RowState == DataRowState.Added) && !(CurrentFRDBase.GetSFRDAvaliacaoRows()[0]["IDModeloAvaliacao", DataRowVersion.Original] == DBNull.Value) && ((long)(CurrentFRDBase.GetSFRDAvaliacaoRows()[0]["IDModeloAvaliacao", DataRowVersion.Original])) == (long)(CurrentFRDBase.GetSFRDAvaliacaoRows()[0]["IDModeloAvaliacao", DataRowVersion.Current]))))
                    {
                        psArgs2.frdID = CurrentFRDBase.ID;
                        psArgs2.modeloAvaliacaoID = CurrentFRDBase.GetSFRDAvaliacaoRows()[0].IDModeloAvaliacao;
                        psArgs2.avaliacaoTabela = CurrentFRDBase.GetSFRDAvaliacaoRows()[0].AvaliacaoTabela;
                        if (CurrentFRDBase.GetSFRDAvaliacaoRows()[0].IsPrazoConservacaoNull())
                            psArgs2.prazoConservacao = 0;
                        else
                            psArgs2.prazoConservacao = CurrentFRDBase.GetSFRDAvaliacaoRows()[0].PrazoConservacao;

                        psArgs2.preservar = CurrentFRDBase.GetSFRDAvaliacaoRows()[0].Preservar;
                    }
                }
                else
                {
                    foreach (GISADataset.SFRDAvaliacaoRow sfrdAv in GisaDataSetHelper.GetInstance().SFRDAvaliacao.Select("", "", DataViewRowState.Added | DataViewRowState.ModifiedCurrent))
                    {
                        PermissoesHelper.ChangeDocPermissionPublicados(sfrdAv.FRDBaseRow.NivelRow.ID, sfrdAv.Publicar);
                        IDs.Add(sfrdAv.FRDBaseRow.IDNivel);
                    }
                }

                // actualização do objecto digital caso exista ou o módulo esteja activo
                rhRow = CurrentFRDBase.NivelRow.GetRelacaoHierarquicaRowsByNivelRelacaoHierarquica().First();
                var objDigital = default(ObjDigital);
                if (rhRow.IDTipoNivelRelacionado >= (long)TipoNivelRelacionado.D && SessionHelper.AppConfiguration.GetCurrentAppconfiguration().IsFedoraEnable())
                {
                    GisaDataSetHelper.HoldOpen ho = new GisaDataSetHelper.HoldOpen(GisaDataSetHelper.GetConnection());
                    try
                    {
                        GisaDataSetHelper.ManageDatasetConstraints(false);
                        if (!PanelAmbitoConteudo1.IsLoaded) PanelAmbitoConteudo1.LoadData(CurrentFRDBase, ho.Connection);
                        if (!PanelIndexacao1.IsLoaded) PanelIndexacao1.LoadData(CurrentFRDBase, ho.Connection);
                        GisaDataSetHelper.ManageDatasetConstraints(true);
                    }
                    catch (System.Data.ConstraintException Ex)
                    {
                        Trace.WriteLine(Ex);
                        GisaDataSetHelper.FixDataSet(GisaDataSetHelper.GetInstance(), ho.Connection);
                    }
                    catch (Exception e)
                    {
                        Trace.WriteLine(e);
                        throw;
                    }
                    finally
                    {
                        ho.Dispose();
                    }
                    
                    // verificar alterações na tipologia e indexação
                    var tipologia = string.Empty;
                    var hasNewTip = Nivel.HasTipologiaChanged(CurrentFRDBase, out tipologia);
                    var assuntos = Nivel.HasIndexacaoChanged(CurrentFRDBase);

                    if (hasNewTip || assuntos != null)
                    {
                        objDigital = FedoraHelper.UpdateTipAssuntos(CurrentFRDBase.NivelRow, hasNewTip ? tipologia : null, assuntos);
                    }
                }

                // actualizar objecto digital caso exista
                var preTransactionAction = new PreTransactionAction();
                var fedArgs = new PersistencyHelper.FedoraIngestPreTransactionArguments();
                preTransactionAction.args = fedArgs;

                preTransactionAction.preTransactionDelegate = delegate(PersistencyHelper.PreTransactionArguments preTransactionArgs)
                {
                    var odComp = this.PanelObjetoDigitalFedora1.GetObjDigitalComp();
                    var odSimples = this.PanelObjetoDigitalFedora1.GetObjDigitalSimples();
                    bool ingestSuccess = true;
                    string msg = null;

                    if (odComp != null)
                        ingestSuccess = SessionHelper.AppConfiguration.GetCurrentAppconfiguration().FedoraHelperSingleton.Ingest(odComp, out msg);
                    else if (odSimples != null && odSimples.Count > 0)
                        odSimples.ForEach(od => ingestSuccess &= SessionHelper.AppConfiguration.GetCurrentAppconfiguration().FedoraHelperSingleton.Ingest(od, out msg));
                    
                    if (ingestSuccess)
                        this.PanelObjetoDigitalFedora1.odHelper.newObjects.Keys.ToList().ForEach(k => { k.pid = this.PanelObjetoDigitalFedora1.odHelper.newObjects[k].pid; });

                    preTransactionArgs.cancelAction = !ingestSuccess;
                    preTransactionArgs.message = msg;
                };

				psArgs1.DocsID = DocsID;

                PostSaveAction postSaveAction = new PostSaveAction();
                PersistencyHelper.UpdatePermissionsPostSaveArguments argsPSAction = new PersistencyHelper.UpdatePermissionsPostSaveArguments();
                argsPSAction.NiveisIDs = IDs;
                argsPSAction.TrusteeID = PermissoesHelper.GrpAcessoPublicados.ID;
                postSaveAction.args = argsPSAction;

                postSaveAction.postSaveDelegate = delegate(PersistencyHelper.PostSaveArguments postSaveArgs)
                {
                    if (!postSaveArgs.cancelAction && argsPSAction.NiveisIDs.Count > 0)
                    {
                        if (psArgs1 != null)
                            idsToUpdate = psArgs1.idsToUpdate;
                    }
                };

				PersistencyHelper.AvaliacaoPublicacaoPreSaveArguments args = new PersistencyHelper.AvaliacaoPublicacaoPreSaveArguments();
				args.psArgs1 = psArgs1;
				args.psArgs2 = psArgs2;

                successfulSave = PersistencyHelper.save(AvaliacaoPublicacao, args, postSaveAction, preTransactionAction, activateOpcaoCancelar);
			}
			else
				successfulSave = PersistencyHelper.save();

            if (successfulSave == PersistencyHelper.SaveResult.successful)
			{
				GisaDataSetHelper.HoldOpen ho = new GisaDataSetHelper.HoldOpen(GisaDataSetHelper.GetConnection());
				try
				{
                    if (CurrentFRDBase.NivelRow.IDTipoNivel == TipoNivel.DOCUMENTAL)
                    {
                        if (idsToUpdate == null) idsToUpdate = new List<string>();
                        idsToUpdate.Add(CurrentFRDBase.NivelRow.ID.ToString());
                        GISA.Search.Updater.updateNivelDocumental(idsToUpdate);
                    }
                    ((frmMain)TopLevelControl).SetServerStatus();
				}
                catch (GISA.Search.UpdateServerException)
                {
                    ((frmMain)TopLevelControl).SetServerStatus();
                }
				catch (Exception ex)
				{
					Trace.WriteLine(ex.ToString());
					throw;
				}
				finally
				{
					ho.Dispose();
				}
			}

			return successfulSave;
		}