/// /// Copyright © 2003-2008 JetBrains s.r.o. /// You may distribute under the terms of the GNU General Public License, as published by the Free Software Foundation, version 2 (see License.txt in the repository root folder). /// using System; using System.ComponentModel; using System.Drawing; using System.Drawing.Drawing2D; using System.Windows.Forms; using JetBrains.Omea.Base; using JetBrains.Omea.Containers; using JetBrains.Omea.GUIControls; using JetBrains.Omea.OpenAPI; using JetBrains.Omea.ResourceTools; namespace JetBrains.Omea { /// /// The bar which shows resources of other types except the ones shown in the /// current tab that are present in the specified resource list. /// internal class SeeAlsoBar : UserControl { /// /// Required designer variable. /// private Container components = null; private ControlPool _iconPool; private ControlPool _linkLabelPool; private ColorScheme _colorScheme; private JetLinkLabel _title; private bool _active; private Font _linkFont; /// /// Horizontal gap between the adjacent labels on the bar. /// protected static readonly int c_nInterLabelHorizontalGap = 12; /// /// Color of the background beneath the control, to simulate the transparent parts. /// private Color _colorUnder; public event SeeAlsoEventHandler SeeAlsoLinkClicked; public SeeAlsoBar() { // This call is required by the Windows.Forms Form Designer. InitializeComponent(); SetStyle( ControlStyles.AllPaintingInWmPaint | ControlStyles.CacheText | ControlStyles.ContainerControl | ControlStyles.ResizeRedraw | ControlStyles.Selectable | ControlStyles.UserPaint, true ); UpdateColors(); _iconPool = new ControlPool( this, new ControlPoolCreateDelegate( OnCreateIcon ) ); _linkLabelPool = new ControlPool( this, new ControlPoolCreateDelegate( OnCreateLinkLabel ) ); _linkFont = new Font( "Tahoma", 8 ); } /// /// Clean up any resources being used. /// protected override void Dispose( bool disposing ) { if( disposing ) { if( components != null ) { components.Dispose(); } _linkFont.Dispose(); } base.Dispose( disposing ); } #region Component Designer generated code /// /// Required method for Designer support - do not modify /// the contents of this method with the code editor. /// private void InitializeComponent() { this._title = new JetLinkLabel(); this.SuspendLayout(); // // _captionLabel // this._title.Font = new System.Drawing.Font( "Tahoma", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((System.Byte) (204)) ); _title.ClickableLink = false; this._title.Location = new System.Drawing.Point( 10, 2 ); this._title.Name = "_title"; this._title.TabIndex = 0; this._title.Text = "See Also:"; this._title.Click += new System.EventHandler( this._captionLabel_Click ); _title.BackColor = Color.Blue; // // SeeAlsoBar // this.Controls.Add( this._title ); this.Font = new System.Drawing.Font( "Tahoma", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((System.Byte) (204)) ); this.Name = "SeeAlsoBar"; this.Size = new System.Drawing.Size( 150, 24 ); this.ResumeLayout( false ); } #endregion [DefaultValue( null )] public ColorScheme ColorScheme { get { return _colorScheme; } set { if( _colorScheme != value ) { _colorScheme = value; UpdateColors(); } } } [DefaultValue( false )] public bool Active { get { return _active; } set { if( _active != value ) { _active = value; UpdateColors(); } } } /// /// Shows the "See also" links for every resource type that is found in the /// specified resource list but not included in the specified array of resource types. /// public void ShowLinks( IResource ownerResource, IResourceList resList, string[] excludeResTypes, int excludeLinkPropId ) { #region Preconditions if ( !Core.UserInterfaceAP.IsOwnerThread ) { throw new InvalidOperationException( "See Also bar must be shown from the UI thread" ); } #endregion Preconditions CountedSet countByTab = new CountedSet(); IntArrayList sourceLinkTypes = IntArrayListPool.Alloc(); try { foreach( IPropType propType in Core.ResourceStore.PropTypes ) { if( propType.HasFlag( PropTypeFlags.SourceLink ) ) { sourceLinkTypes.Add( propType.Id ); } } WorkspaceManager wspMgr = Core.WorkspaceManager as WorkspaceManager; IResource activeWorkspace = Core.WorkspaceManager.ActiveWorkspace; bool filterViewsExclusive = false; if ( ownerResource.Type == "SearchView" && !ownerResource.HasProp( "ShowInAllTabs" ) ) { filterViewsExclusive = true; } int outsideWorkspaceCount = 0, unfoundCount = 0; IResourceList actualRcs = resList; lock( actualRcs ) { foreach( IResource res in actualRcs.ValidResources ) { string resType = res.Type; if( resType == "Fragment" ) { resType = res.GetStringProp( Core.Props.ContentType ); // guard for broken DB (OM-12080) if( resType == null || !Core.ResourceStore.ResourceTypes.Exist( resType ) ) { continue; } } if( activeWorkspace != null && !activeWorkspace.HasLink( wspMgr.Props.WorkspaceVisible, res ) ) { outsideWorkspaceCount++; continue; } if( excludeResTypes != null && IsTabType( resType, excludeResTypes ) ) continue; if( excludeLinkPropId >= 0 && res.HasProp( excludeLinkPropId ) ) continue; if ( filterViewsExclusive && Core.ResourceTreeManager.AreViewsExclusive( resType ) ) continue; bool found = false; if( Core.ResourceStore.ResourceTypes[ resType ].HasFlag( ResourceTypeFlags.FileFormat ) ) { foreach( int sourceLinkType in sourceLinkTypes ) { if( res.HasProp( sourceLinkType ) ) { string tabId = Core.TabManager.FindLinkPropTab( sourceLinkType ); if( tabId != null ) { countByTab.Add( tabId ); } found = true; break; } } } else { string resourceTabId = Core.TabManager.FindResourceTypeTab( resType ); if( resourceTabId != null ) { countByTab.Add( resourceTabId ); found = true; } } if( !found ) { unfoundCount++; } } } if( countByTab.Count == 0 && unfoundCount == 0 && outsideWorkspaceCount == 0 ) { Visible = false; return; } _iconPool.MoveControlsToPool(); _linkLabelPool.MoveControlsToPool(); int x = _title.Right + 4; int labelCount = 0; for( int i = 0; i < Core.TabManager.Tabs.Count; i++ ) { string tabId = Core.TabManager.Tabs[ i ].Id; int count = countByTab[ tabId ]; if( count > 0 ) { string text = Core.TabManager.Tabs[ i ].Name + " (" + count.ToString() + ")"; AddLinkLabel( tabId, text, ref x ); labelCount++; } } if( (labelCount > 1 || unfoundCount > 0) && (excludeResTypes != null || excludeLinkPropId >= 0) ) { AddLinkLabel( "", "All Results (" + (resList.Count - outsideWorkspaceCount) + ")", ref x ); } if( outsideWorkspaceCount > 0 ) { string sDefaultWspName = ((WorkspaceManager)Core.WorkspaceManager).Props.DefaultWorkspaceName; AddLinkLabel( "
", String.Format("{0} Workspace ({1})", sDefaultWspName, resList.Count), ref x ); } _iconPool.RemovePooledControls(); _linkLabelPool.RemovePooledControls(); Visible = true; } finally { IntArrayListPool.Dispose( sourceLinkTypes ); } } private void AddLinkLabel( object tag, string text, ref int x ) { JetLinkLabel linkLabel = (JetLinkLabel) _linkLabelPool.GetControl(); linkLabel.Text = text; linkLabel.Location = new Point( x, 2 ); linkLabel.Tag = tag; SetLinkColor( linkLabel ); x += linkLabel.PreferredWidth + 12; } private void UpdateColors() { if( _colorScheme != null ) { // Labels color foreach( Control control in Controls ) SetLinkColor( control ); // Bar caption color (foreground) _title.ForeColor = _colorScheme.GetColor( "SeeAlso.Caption" + ActiveColorSuffix ); } Invalidate(false); } /// /// Applies back and fore color to a control. /// protected void SetLinkColor( Control control ) { if( _colorScheme != null ) { control.ForeColor = _colorScheme.GetColor( "SeeAlso.Link" + ActiveColorSuffix ); control.BackColor = _colorScheme.GetColor( "SeeAlso.Background" + ActiveColorSuffix ); } } /// /// Color name suffix which denotes the active/inactive state of the control. /// protected string ActiveColorSuffix { get { return _active ? "Active" : "Inactive"; } } /// /// Checks if the type is present in the specified array. /// private bool IsTabType( string resType, string[] tabTypes ) { foreach( string tabType in tabTypes ) { if( resType == tabType ) { return true; } } return false; } /// /// Creates an icon to be displayed in the bar. /// private Control OnCreateIcon() { ImageListPictureBox pbox = new ImageListPictureBox(); pbox.ImageList = Core.ResourceIconManager.ImageList; return pbox; } /// /// Creates a LinkLabel to be displayed in the bar. /// private Control OnCreateLinkLabel() { JetLinkLabel linkLabel = new JetLinkLabel(); linkLabel.AutoSize = true; linkLabel.Font = _linkFont; linkLabel.Click += new EventHandler( OnLinkLabelClicked ); return linkLabel; } private void OnLinkLabelClicked( object sender, EventArgs e ) { // process asynchronously because the SeeAlso handler will dispose the label JetLinkLabel senderLabel = (JetLinkLabel) sender; if( SeeAlsoLinkClicked != null ) { bool mainWorkspace = false; string tabId = senderLabel.Tag as string; if( tabId == "
" ) { mainWorkspace = true; tabId = ""; } Core.UIManager.QueueUIJob( new SeeAlsoEventHandler( SeeAlsoLinkClickedAsync ), new object[] {this, new SeeAlsoEventArgs( tabId, mainWorkspace )} ); } } private void SeeAlsoLinkClickedAsync( object sender, SeeAlsoEventArgs e ) { SeeAlsoLinkClicked( this, e ); } private void _captionLabel_Click( object sender, EventArgs e ) { OnClick( EventArgs.Empty ); } protected override void OnPaint(PaintEventArgs e) { // Pick the background color from the scheme Color colorBack = ColorScheme.GetColor( _colorScheme, "SeeAlso.Background" + (_active ? "Active" : "Inactive"), Color.Black ); // There's a cutting on the left of the bar (diagonal one). // This is the size of its bounding box, equal to the bar height, as it is at 45 deg. int nCuttingBoxSize = ClientRectangle.Height; ////////////////// // Paint Background //// // Rectangular (main) part Rectangle rectBack = ClientRectangle; rectBack.X += nCuttingBoxSize; // Leave some space on the left for the cutting rectBack.Width -= nCuttingBoxSize; using( Brush brush = new SolidBrush( colorBack ) ) e.Graphics.FillRectangle( brush, rectBack ); //// // Cutting on the left // Points of the cutting triangle: left-top, right-top, right-bottom Point[] ptCuttingTopRight = new Point[] {new Point( 0, 0 ), new Point( nCuttingBoxSize, 0 ), new Point( nCuttingBoxSize, nCuttingBoxSize )}; Point[] ptCuttingBottomLeft = new Point[] {new Point( 0, 0 ), new Point( 0, nCuttingBoxSize ), new Point( nCuttingBoxSize, nCuttingBoxSize )}; byte[] types = new byte[] {(byte) PathPointType.Start, (byte) PathPointType.Line, (byte) PathPointType.Line}; using( Brush brushMyBackground = new SolidBrush( colorBack ) ) using( Brush brushForeignBackground = new SolidBrush( Undercolor ) ) using( GraphicsPath pathTopRight = new GraphicsPath( ptCuttingTopRight, types ) ) using( GraphicsPath pathBottomLeft = new GraphicsPath( ptCuttingBottomLeft, types ) ) { e.Graphics.FillPath( brushMyBackground, pathTopRight ); e.Graphics.FillPath( brushForeignBackground, pathBottomLeft ); } } /// /// Color beneath the control. /// public Color Undercolor { get { return _colorUnder; } set { if(value.A != 255) throw new ArgumentException("Transparent colors not allowed.", "value"); _colorUnder = value; Invalidate(false); } } /// /// Layout of the bar has to be recalculated, layout the controls. /// protected override void OnLayout(LayoutEventArgs levent) { // Relocate the controls int x = -1; // The current x-coordinate int nUpperGap; // Gap above the current control, or its location's y-coord int nMyHeight = Height; // Height of the bar foreach( Control control in Controls ) { nUpperGap = (nMyHeight - control.Height) / 2; if( x < 0 ) // For the first control, calc the starting X according to the cutting x = nUpperGap + control.Height; // Move control.Location = new Point( x, nUpperGap ); // Skip the control x += control.Width + c_nInterLabelHorizontalGap; } // Apply the visual changes Invalidate(false); } } public class SeeAlsoEventArgs : EventArgs { private string _tabId; private bool _mainWorkspace; internal SeeAlsoEventArgs( string tabId, bool mainWorkspace ) { _tabId = tabId; _mainWorkspace = mainWorkspace; } public string TabId { get { return _tabId; } } public bool MainWorkspace { get { return _mainWorkspace; } } } public delegate void SeeAlsoEventHandler( object sender, SeeAlsoEventArgs e ); }