void SetupDebaterColumn(string prop, CellRendererTextAdv.Type type) { int colNum = treeDebaters.Columns.Length; CellRendererTextAdv renderer = new CellRendererTextAdv(type, store, colNum); TreeViewColumn col = treeDebaters.AppendColumn(prop, renderer, CellDataFuncDefault); renderer.MyEdited += delegate(CellRendererTextAdv sender, string path, string newText) { CellRendererEdited(sender, path, newText, colNum); }; col.Resizable = true; col.Clicked += ((_, __) => SetSortColumn(colNum)); (treeDebaters.Model as TreeModelSort).SetSortFunc(colNum, delegate(TreeModel model, TreeIter a, TreeIter b) { return(SortDebaters(model, a, b, colNum)); }); }
void CellRendererEdited(CellRendererTextAdv sender, string pathStr, string newText, int colNum) { TreeModelSort model = (TreeModelSort)treeDebaters.Model; TreePath path = new TreePath(pathStr); TreeIter iter = TreeIter.Zero; model.GetIter(out iter, path); EditableDebater d = (EditableDebater)model.GetValue(iter, 0); try { ColumnInfo prop = columns[treeDebaters.Columns[colNum].Title]; // This parses the given new string, // and updates the data in store prop.parseAndSet(d, newText); // existing Debater: Update Data in (possibly) existing Rounds // tries to keep data consisting, but there's no guarantee // BlackList/WhiteList and ExtraInfo are not // used in RoundDebater, so skip this by condition colNum<4 if (newDebaterPath == null && colNum < 4) { var rd = new EditableDebater(d); var p = prop.get(d); // Only simple Renaming of Role is possible if Rounds exist if (colNum == 3 && Tournament.I.Rounds.Count > 0 && ((d.Role.IsTeamMember != rd.Role.IsTeamMember) || (d.Role.IsJudge != rd.Role.IsJudge))) { MiscHelpers.ShowMessage(this, "Changing Role from Judge to TeamMember (or vice versa)" + " is not possible since Rounds are already set.", MessageType.Error); // reset to old role... d.Role = rd.Role; return; } // check if new TeamName is already present if (colNum == 3 && d.Role.IsTeamMember) { int n = 0; foreach (object[] row in store) { EditableDebater d_ = (EditableDebater)row[0]; if (!d.Equals(d_) && d_.Role.TeamName == d.Role.TeamName) { n++; } } if (n == 3) { MiscHelpers.ShowMessage(this, "New TeamName is already present in three other Debaters.", MessageType.Error); // reset to old role... d.Role = rd.Role; return; } } // check for duplicate if (colNum < 3) { // need a temporary flag, throwing exceptions in delegates doesnt work... // the following flag stuff isn't elegant, but it should work bool flag = false; model.Foreach((model_, _, iter_) => { if (!iter.Equals(iter_)) { EditableDebater d_ = (EditableDebater)model_.GetValue(iter_, 0); if (d_.Equals(d)) { // reset to old value... prop.get(rd).Set(d); flag = true; return(true); } } return(false); }); if (flag) { throw new TargetInvocationException(new Exception("Debater exists.")); } } // keep data consistent in existing rounds foreach (RoundData round in Tournament.I.Rounds) { foreach (RoomData room in round.Rooms) { foreach (RoundDebater rd_ in room.GetRoomMembers()) { if (rd_ == null) { continue; } if (rd_.Equals(rd)) { p.UnsafeSetRoundDebater(rd_); } if (rd_.Role.TeamName == rd.Role.TeamName) { rd_.Role.TeamName = d.Role.TeamName; } } } if (rd.Role.IsTeamMember) { foreach (TeamData team in round.AllTeams) { foreach (RoundDebater rd_ in team) { if (rd_.Equals(rd)) { p.UnsafeSetRoundDebater(rd_); } if (rd_.Role.TeamName == rd.Role.TeamName) { rd_.Role.TeamName = d.Role.TeamName; } } } } else if (rd.Role.IsJudge) { foreach (RoundDebater rd_ in round.AllJudges) { if (rd_.Equals(rd)) { p.UnsafeSetRoundDebater(rd_); } } } } // Renaming TeamName needs extra Handling if (colNum == 3 && rd.Role.IsTeamMember && d.Role.IsTeamMember) { foreach (object[] row in store) { EditableDebater d_ = (EditableDebater)row[0]; if (d_.Role.TeamName == rd.Role.TeamName) { d_.Role.TeamName = d.Role.TeamName; } } } } // newDebater is entered... else if (newDebaterPath != null && colNum < 3) { // continue with entering data (goto next column) // as idle so that cells are resized GLib.Idle.Add(delegate { treeDebaters.SetCursor(ConvertStorePathToModelPath(newDebaterPath), treeDebaters.Columns[colNum + 1], true); return(false); }); } else if (newDebaterPath != null) { // new Debater entered completely (at least all necessary data) iter = TreeIter.Zero; if (store.GetIter(out iter, newDebaterPath)) { // as idle to prevent gtk critical (no idea why this happens) GLib.Idle.Add(delegate { store.Remove(ref iter); newDebaterPath = null; if (IsNotInStore(d)) { store.AppendValues(d); SaveDebaters(); } else { MiscHelpers.ShowMessage(this, "Debater exists.", MessageType.Error); } UpdateDebatersInfo(); btnDebaterAdd.GrabFocus(); return(false); }); } } // Gui stuff treeDebaters.ColumnsAutosize(); // ugly method of resorting the TreeSortModel... SortType st; int sortColumn; model.GetSortColumnId(out sortColumn, out st); if (st == SortType.Descending) { model.SetSortColumnId(sortColumn, SortType.Ascending); model.SetSortColumnId(sortColumn, SortType.Descending); } else { model.SetSortColumnId(sortColumn, SortType.Descending); model.SetSortColumnId(sortColumn, SortType.Ascending); } // save data from store if not adding new debater if (newDebaterPath == null) { SaveDebaters(); } } catch (TargetInvocationException e) { MessageDialog md = new MessageDialog(this, DialogFlags.Modal, MessageType.Error, ButtonsType.OkCancel, e.InnerException.Message + ". Try again?"); md.DefaultResponse = ResponseType.Ok; ResponseType r = (ResponseType)md.Run(); md.Destroy(); if (r == ResponseType.Ok) { // As Idle otherwise Editable isn't destroyed correctly GLib.Idle.Add(delegate { sender.TempEditString = newText; treeDebaters.SetCursor(path, treeDebaters.Columns[colNum], true); return(false); }); } else { if (newDebaterPath == null) { return; } iter = TreeIter.Zero; if (store.GetIter(out iter, newDebaterPath)) { // remove not finished new debater, // with idle call, // prevents Gtk critical filter model assertion. GLib.Idle.Add(delegate { newDebaterPath = null; store.Remove(ref iter); return(false); }); } } } }