/// <summary> /// Displays one or two versions of a file in a diff-like view. /// </summary> /// <param name="fid"> File id </param> /// <param name="userName"> User name </param> /// <param name="vid1"> Version id on the left. If 0, the base version. </param> /// <param name="vid2"> Version id on the right. If 0, the latest change. </param> /// <param name="ignoreWhiteSpace"> Whether the diff algorithm should ignore white space. </param> private void DisplayFile(int fid, string userName, int vid1, int vid2, bool ignoreWhiteSpace) { var fileQuery = from fl in DataContext.ChangeFiles where fl.Id == fid select fl; if (fileQuery.Count() != 1) { ErrorOut("No such file!"); return; } HintsData.InDiffView = true; ChangeFile file = fileQuery.Single(); AbstractedFileVersion[] versions = GetVersionsWithTextAbstract(fid); if (versions.Length == 0) { ErrorOut("No versions submitted for this file."); return; } if (vid1 == 0) { // By default, shows the diff between the last reviewed version of a file and the // latest version of that file. var latestReview = GetLatestUserReviewForChangeList(userName, file.ChangeListId); if (latestReview != null) { foreach (var version in versions) { if (latestReview.TimeStamp.CompareTo(version.TimeStamp) > 0) vid1 = version.Id; } // If the user has reviewed the latest change, they're probably taking another // look, so show them the diff between the latest and latest-1 versions. if (vid1 == versions[versions.Length - 1].Id && versions.Length > 1) vid1 = versions[versions.Length - 2].Id; } // If no version picked above (because user has not reviewed the changelist) // then just show the user the diff of the entire file change history. if (vid1 == 0) vid1 = versions[0].Id; } if (vid2 == 0) vid2 = versions[versions.Length - 1].Id; DisplayPageHeader(file.ServerFileName); // Enclosing div (used to get shrink-to-contents behaviour for inner div). var fileVersionsDivOuter = new Panel() { CssClass = "CssOuterDiv" }; ActivePage.Controls.Add(fileVersionsDivOuter); var fileVersionsDiv = new Panel() { CssClass = "CssFileVersions" }; fileVersionsDivOuter.Add(fileVersionsDiv); var fileVersionsFieldSet = new OptionSection(false) { Header = "File Versions" } .AddTo(fileVersionsDiv); string name = file.ServerFileName; int lastForwardSlash = name.LastIndexOf('/'); if (lastForwardSlash >= 0) name = name.Substring(lastForwardSlash + 1); RadioButtonList leftList = new RadioButtonList(); fileVersionsFieldSet.Body.Add(leftList); leftList.ID = "LeftFileVersion"; leftList.Items.AddRange( (from ver in versions select new ListItem(ComputeMoniker(name, ver), ver.Id.ToString()) { Selected = ver.Id == vid1 }).ToArray()); RadioButtonList rightList = new RadioButtonList(); fileVersionsFieldSet.Body.Add(rightList); rightList.ID = "RightFileVersion"; rightList.Items.AddRange( (from ver in versions select new ListItem(ComputeMoniker(name, ver), ver.Id.ToString()) { Selected = ver.Id == vid2 }).ToArray()); if (versions.Length > 1) HintsData.HaveMultipleVersions = true; var selectVersionsPanel = new Panel() { CssClass = "ButtonPanel" } .AddTo(fileVersionsFieldSet.Body); var selectVersions = new Button() { Text = "Select", ID = "selectversionsbutton", CssClass = "button" }.AddTo(selectVersionsPanel); selectVersions.Click += new EventHandler(selectVersions_Clicked); var filesQuery = (from fl in DataContext.ChangeFiles where fl.ChangeListId == file.ChangeListId join vr in DataContext.FileVersions on fl.Id equals vr.FileId where vr.Text != null orderby vr.Id select fl).Distinct(); AddLabel("<br><br>"); BuildNavigationTable(file, filesQuery, vid1, vid2, ignoreWhiteSpace, 0); if (!Page.IsPostBack) { int baseReviewId = GetBaseReviewId(userName, file.ChangeListId); ClientScript.RegisterClientScriptBlock(this.GetType(), "username", "<script type=\"text/javascript\">var username = \"" + userName + "\";</script>"); if (vid1 == vid2) // The same file - diff will be null. { var versionQuery = from vr in DataContext.FileVersions where vr.Id == vid1 select vr; if (versionQuery.Count() == 1) { FileVersion version = versionQuery.Single(); using (StreamCombiner text = GetFileStream(version)) { if (text != null) { ActivePage.Controls.Add(GenerateFileDiffView( text, vid1, GetComments(vid1, baseReviewId), name, null, vid1, null, null, true, null, name)); } else { ErrorOut("No file here..."); } } } else { ErrorOut("Multiple files detected here. Suspect a bug - please report!"); } } else { var versionQuery = from vr in DataContext.FileVersions where vr.Id == vid1 || vr.Id == vid2 select vr; if (versionQuery.Count() == 2) { FileVersion[] leftRight = versionQuery.ToArray(); FileVersion left, right; if (leftRight[0].Id == vid1) { left = leftRight[0]; right = leftRight[1]; } else { left = leftRight[1]; right = leftRight[0]; } if (left.Revision == right.Revision) { //@TODO: I disabled this due to some issue I was having, but I can't remember what it // was. Need to sit down and figure out what the issue was. //if (left.IsFullText && !right.IsFullText && !ignoreWhiteSpaces) //{ // StreamCombiner leftReader = new StreamCombiner(left.Text); // StreamCombiner rightReader = new StreamCombiner(left.Text, right.Text); // StreamCombiner rawDiffReader = new StreamCombiner(right.Text); // ActivePage.Controls.Add(GenerateFileDiffView( // leftReader, vid1, GetComments(vid1, baseReviewId), // ComputeMoniker(name, left), rightReader, vid2, GetComments(vid2, baseReviewId), // ComputeMoniker(name, right), true, rawDiffReader, name)); // leftReader.Close(); // rightReader.Close(); // rawDiffReader.Close(); //} //else if (!left.IsFullText && right.IsFullText && !ignoreWhiteSpaces) //{ // StreamCombiner leftReader = new StreamCombiner(right.Text, left.Text); // StreamCombiner rightReader = new StreamCombiner(right.Text); // StreamCombiner rawDiffReader = new StreamCombiner(left.Text); // ActivePage.Controls.Add(GenerateFileDiffView( // rightReader, vid2, GetComments(vid2, baseReviewId), // ComputeMoniker(name, right), leftReader, vid1, GetComments(vid1, baseReviewId), // ComputeMoniker(name, left), false, rawDiffReader, name)); // leftReader.Close(); // rightReader.Close(); // rawDiffReader.Close(); //} //else { DisplayDiff(left, right, name, baseReviewId, ignoreWhiteSpace); } } else { DisplayDiff(left, right, name, baseReviewId, ignoreWhiteSpace); } } else { ErrorOut("Could not get the two files. Either a bug, or incorrect version specified!"); } } AddLabel("<br>"); } BuildNavigationTable(file, filesQuery, vid1, vid2, ignoreWhiteSpace, 1); }
/// <summary> /// Displays and allows changing user preferences. /// </summary> /// <param name="sourceUrl"> The URL from which the request came. </param> private void DisplaySettings(string sourceUrl) { DisplayPageHeader("Personalize Malevich to your taste!"); Panel page = new Panel() { CssClass = "CssSettingsPage" }; ActivePage.AddBreak(); ActivePage.Controls.Add(page); UserContext uc = CurrentUserContext; var settings = new Panel() { CssClass = "Accordion Settings" }; page.Add(settings); // Fonts string fonts = System.Configuration.ConfigurationSettings.AppSettings["fonts"]; if (fonts != null) { var section = new OptionSection() { Header = "File Viewer Font", Description = "Choose the font to use when viewing files or diffs." } .AddTo(settings); RadioButtonList textFonts = new RadioButtonList() { ID = "TextFont" } .AddTo(section.Body); string[] fontValues = fonts.Split(';'); foreach (string font in fontValues) { Match m = FontParser.Match(font); if (!m.Success) continue; string fontName = m.Groups["fontname"].Value; ListItem item = new ListItem(); item.Text = fontName; item.Value = fontName; if (uc.TextFont != null && uc.TextFont.EqualsIgnoreCase(fontName)) item.Selected = true; textFonts.Items.Add(item); } } { // Font size var section = new OptionSection() { Header = "File Viewer Font Size", Description = "Choose a font for viewing files and diffs." } .AddTo(settings); RadioButtonList textSize = new RadioButtonList() { ID = "TextSize" } .AddTo(section.Body); int defaultTextSize = 0; if (uc.TextSize != null) defaultTextSize = uc.TextSize.Value; string[] textSizes = { "small", "medium", "large" }; for (int i = 0; i < textSizes.Length; ++i) { ListItem item = new ListItem(); item.Text = textSizes[i]; item.Value = textSizes[i]; if (i == defaultTextSize) item.Selected = true; textSize.Items.Add(item); } } { // Max chars per line var section = new OptionSection() { Header = "File Viewer Line Length", Description = "Choose number of characters per line in the file viewer and differ." } .AddTo(settings); "Enter a value between 80 and 160, or clear the value to revert to the project default<p/>" .AsLiteral() .AddTo(section.Body); TextBox tb = new TextBox() { ID = "MaxLineLength", Text = (uc.MaxLineLength != null ? uc.MaxLineLength.Value.ToString() : "") }; section.Body.Add(tb); } // Spaces in a tab string tabOverrideAllowed = System.Configuration.ConfigurationSettings.AppSettings["allowTabOverride"]; if ("true".Equals(tabOverrideAllowed)) { var section = new OptionSection() { Header = "File Viewer Tab Display Format", Description = "Enter '\\t', 'n spaces', or nothing for site default.<p/>" } .AddTo(settings); var tb = new TextBox() { ID = "SpacesPerTab" }; if (uc.SpacesPerTab != null) tb.Text = uc.SpacesPerTab.Value == -1 ? "\\t" : (uc.SpacesPerTab.Value + " spaces"); section.Body.Add(tb); } { // Unified view var section = new OptionSection() { Header = "File Viewer Diff Style", Description = "Use windiff-style differ?" } .AddTo(settings); RadioButtonList windiff = new RadioButtonList() { ID = "UnifiedViewer" }; section.Body.Add(windiff); windiff.Items.Add(new ListItem() { Text = "Yes", Value = "yes" }); windiff.Items.Add(new ListItem() { Text = "No", Value = "no" }); windiff.Items[(uc.UnifiedDiffView ?? false) ? 0 : 1].Selected = true; } { // Comment creation mouse-click options. var section = new OptionSection() { Header = "Commenting Mode", Description = "Choose how comments are created." } .AddTo(settings); var rbl = new RadioButtonList() { ID = "CommentClickMode" }; section.Body.Add(rbl); rbl.Items.Add(new ListItem() { Text = "Single click anywhere creates comment.", Value = CommentClickMode.SingleClickAnywhere.ToString(), }); rbl.Items.Add(new ListItem() { Text = "Double click anywhere creates comment.", Value = CommentClickMode.DoubleClickAnywhere.ToString(), }); rbl.Items.Add(new ListItem() { Text = "Single click on line number creates comment", Value = CommentClickMode.ClickLineNumber.ToString(), }); rbl.Items[(int)uc.CommentClickMode].Selected = true; } { // Empty comment collapse var section = new OptionSection() { Header = "Comment Collapsing", Description = "Automatically collapse empty comments?" } .AddTo(settings); RadioButtonList autoCollapse = new RadioButtonList() { ID = "AutoCollapseComments" }; section.Body.Add(autoCollapse); autoCollapse.Items.Add(new ListItem() { Text = "Yes", Value = "yes" }); autoCollapse.Items.Add(new ListItem() { Text = "No", Value = "no" }); autoCollapse.Items[(uc.AutoCollapseComments ?? true) ? 0 : 1].Selected = true; } { // Hints var section = new OptionSection() { Header = "Hints", Description = "Show hints?" } .AddTo(settings); RadioButtonList hints = new RadioButtonList() { ID = "Hints" }; section.Body.Add(hints); hints.Items.Add(new ListItem() { Text = "Yes", Value = "yes" }); hints.Items.Add(new ListItem() { Text = "No", Value = "no" }); if ((uc.HintsMask ?? 0) != -1) hints.Items.Add(new ListItem() { Text = "Reset hints", Value = "reset" }); hints.Items[(uc.HintsMask ?? 0) != -1 ? 0 : 1].Selected = true; } var buttons = new Panel() { CssClass = "CssButtonBar" } .AddTo(page); var submit = new Button() { Text = "Submit", CssClass = "button", }.AddTo(buttons); submit.Click += new EventHandler(changeUserPrefs_Clicked); var cancel = new Button() { Text = "Cancel", CssClass = "button", }.AddTo(buttons); cancel.Click += new EventHandler(delegate(object sender, EventArgs e) { Response.Redirect(sourceUrl); }); }