示例#1
0
		/// <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);
		}
示例#2
0
		/// <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);
			});
		}