Esempio n. 1
0
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            if (parameter != null && (string)parameter == "pin")
            {
                return((bool?)value == true ? Resources.Str_Unpin : Resources.Str_Pin);
            }
            var pi = value as PowerItem;

            if (pi == null)
            {
                return(Resources.Err_CantGetTooltip);
            }
            if (!pi.IsNotPureControlPanelFlowItem)
            {
                return(Resources.Str_CplElement);
            }
            if (pi.IsSpecialObject)
            {
                var cmd = Util.GetOpenCommandForClass(pi.Argument);
                if (cmd == null)
                {
                    return(pi.FriendlyName + Resources.Str_Library);
                }
                return(cmd.Item1);
            }
            try
            {
                return(PowerItemTree.GetResolvedArgument(pi));
            }
            catch (IOException)
            {
                return(Resources.Err_CantGetTooltip);
            }
        }
Esempio n. 2
0
        //------------------------------------------

        /// <summary>
        /// Starts or cancels asynchronous search and sets the data source for MFU list
        /// depending on text in search field
        /// </summary>
        private void SearchBoxTextChanged(object sender, TextChangedEventArgs e)
        {
            PowerItemTree.SearchTreeCancel();                  //first always cancel the current search
            var q = SearchBox.Text.Trim().ToLowerInvariant();  //ignore spaces an case

            if (!String.IsNullOrWhiteSpace(q) && q.Length > 1) //we can probably start search
            {
                //Clear selection always before (re)starting search or preparing the WebSearch.
                //For the Search this will help P8 to handle Enter properly, because sometimes,
                //if you're REALLY fast, UI is repainted BEFORE Items collection is being actually
                //updated, along with SelectedItem, so you see and try launching item different
                //from one being actually launched.
                dataGrid.SelectedIndex = -1;
                dataGrid.SelectedItem  = null;
                if (q[1] != ' ')                        //not web search
                {
                    dataGrid.ItemsSource = _searchView; //switch MFU list to search results and kisk search invoker
                    var t = PowerItemTree.SearchTreeCancel();
                    Util.ForkPool(() => PowerItemTree.SearchTree(q, _searchData, ExpandGroup, t), "Search root for " + q);
                }
                //else{} //web search - no actions from our side here, wait for enter
            }
            else //no search
            {
                dataGrid.ItemsSource    = MfuItems; //show MFU list
                SearchMarker.Visibility = Visibility.Hidden; //Hide search marker if any
            }
        }
Esempio n. 3
0
 /// <summary>
 /// Removes item from user list.
 /// </summary>
 /// <param name="item">Item to remove. This method is called from UI, which converts
 /// the string paths (potentially not mapped to PowerItem originally) to new PowerItems
 /// when needed, so that's why there is no overload to remove string from the list.</param>
 public static void RemoveCustom(PowerItem item)
 {
     lock (UserList)
     {
         UserList.Remove(PowerItemTree.GetResolvedArgument(item));
         _writeUserList = true;
         UpdateStartMfuSync();
     }
 }
Esempio n. 4
0
 /// <summary>
 /// Safely invokes passed item and hides the butonstack - as it is done for the grid
 /// Used in other code as well, like in the search bar handlers, because they behave
 /// like invoking something from the grid.
 /// </summary>
 /// <param name="item">Grid's selected item (usually)</param>
 private void InvokeFromDataGrid(PowerItem item)
 {
     try
     {
         PowerItemTree.SearchTreeCancel(); //if search thread is really slow compared to this UI one,
         //the following call may execute before search was finished, and MFUList may receive
         //"process launched" event and update itself, which will cause InvalidOperationException
         item.Invoke();
     }
     catch (Exception ex)
     {
         Util.DispatchCaughtException(ex);
     }
     Hide();
 }
Esempio n. 5
0
        /// <summary>
        /// When not null value is passed as argument, tries to perform the command
        /// related to the argument passed via the system Verb engine. Works for
        /// non-folders.<br/>
        /// If RunAsAdmin verb is passed and this PowerItem instance is Folder, flag
        /// is converted to boolean true instructing ResolveItem() that, if available,
        /// Common start menu folder should be used instead of user one. This is not
        /// used for non-folder items and won't work for folders not under Start menu,
        /// even there's corresponding CSIDLs.<br/>
        /// If null value is passed, then it simply runs the PowerItem. Consult Invoke()
        /// xml-doc on how this can be performed.
        /// </summary>
        /// <param name="verb">One from <code>API.SEVerbs</code> constants, or null/empty
        /// string, which means "no command"</param>
        public void InvokeVerb(string verb)
        {
            //Shell namespaces and Power8 classes
            if (SpecialFolderId != API.Csidl.INVALID)
            {
                if (string.IsNullOrEmpty(Argument))
                {
                    Util.DisplaySpecialFolder(SpecialFolderId);
                    return;
                }
                if (SpecialFolderId == API.Csidl.POWER8CLASS)
                {
                    Util.InstanciateClass(Argument);
                    return;
                }
                if (SpecialFolderId == API.Csidl.POWER8IMMERSIVE)
                {
                    Util.TryInvokeAppUserModelId(Argument);
                    return;
                }
            }
            //All the other stuff: FS-resolvable
            var psi = PowerItemTree.ResolveItem(this, IsFolder && verb == API.SEVerbs.RunAsAdmin);

            if (!string.IsNullOrEmpty(verb) && IsFile)  //pass verb
            {
                psi.Verb = verb;
            }
            if (psi.Arguments.StartsWith("\\\\"))       //network items may be only directly launched
            {
                psi.UseShellExecute = false;
            }
            try
            {
                Util.CreateProcess(startInfo: psi);
            }
            catch (Win32Exception w32E)            //Any exception will be handled really out of here, but we
            {                                      //shall report proper error
                if (w32E.NativeErrorCode == 0x483) //1155, e.g. when doing "runas" on "*.hlp"
                {
                    psi.Verb = null;
                    Util.CreateProcess(startInfo: psi);
                    throw new InvalidProgramException(Resources.Err_StartAsAdminFailed + w32E.Message);
                }
                throw;
            }
        }
Esempio n. 6
0
 public static int MoveCustomListItem(PowerItem which, PowerItem where)
 {
     lock (LastList)
     {
         //1. Change order in UserList
         var argFrom = PowerItemTree.GetResolvedArgument(which);
         var argTo   = PowerItemTree.GetResolvedArgument(@where);
         int idxFrom = UserList.IndexOf(argFrom);
         int idxTo   = UserList.IndexOf(argTo);
         UserList.RemoveAt(idxFrom);
         UserList.Insert(idxTo + idxFrom > idxTo ? 1 : 0, argFrom);
         //2. Update LastList
         LastList.Clear();
         GetMfuFromCustomData().ForEach(m => LastList.Add(m.Clone()));
         //3. Change order in MfuList - with respect to pinning
         StartMfu.Move(StartMfu.IndexOf(which), StartMfu.IndexOf(where));
         return(StartMfu.IndexOf(which));
     }
 }
Esempio n. 7
0
        public static void Add2Custom(PowerItem item, string fullPath = null)
        {
            var arg = item == null ? fullPath : PowerItemTree.GetResolvedArgument(item);
            var idx = UserList.IndexOf(arg);

            if (idx == UserList.Count - 1 && UserList.Count > 0) //Already in list and top item
            {
                return;
            }
            if (idx != -1) //Already in list, move to top
            {
                UserList.RemoveAt(idx);
            }
            UserList.Add(arg); //Including case where item not in list
            if (SettingsManager.Instance.MfuIsCustom && fullPath == null)
            {
                UpdateStartMfuSync(); //Refresh
            }
        }
Esempio n. 8
0
        /// <summary>
        /// Synchronous getter of an icon for PowerItem
        /// </summary>
        /// <param name="item">PowerItem we need icon extracted for</param>
        /// <param name="iconNeeded">type of icon needed - small or large</param>
        /// <returns>ImageContainer with ImageSources extracted. Can be null.</returns>
        public static ImageContainer GetImageContainerSync(PowerItem item, API.Shgfi iconNeeded)
        {
            Log.Raw("begin>>>>>>>>>>>>>>>", item.FriendlyName);
            //Checking if there's cached ImageContainer
            string resolvedArg, descr;

            try
            {
                resolvedArg = PowerItemTree.GetResolvedArgument(item);
                descr       = GetObjectDescriptor(item, resolvedArg);
            }
            catch (IOException)
            {
                return(null);
            }
            lock (Cache)
            {
                var container = (ImageContainer)(Cache.ContainsKey(descr) ? Cache[descr] : null);
                Log.Fmt("arg<={0}, descr<={1}, container<={2}", resolvedArg, descr,
                        (container != null ? "not " : "") + "null");
                if (container == null) //No cached instance
                {
                    container = new ImageContainer(resolvedArg, descr, item.SpecialFolderId);
                    Cache.Add(descr, container);
                    if (iconNeeded == API.Shgfi.SMALLICON)
                    {
                        container.ExtractSmall();
                    }
                    else
                    {
                        container.ExtractLarge();
                    }
                }
#if DEBUG
                Log.Raw("end<<<<<<<<<<<<<<", item.FriendlyName);
#endif
                return(container);
            }
        }
Esempio n. 9
0
        /// <summary>
        /// Returns string, of a Path kind, that can be passed to a system, and will
        /// represent the passed PowerItem. Depending on Caller Name, may invoke
        /// automatic Link resolution for Link PowerItems. "Denamespaces" the
        /// passed ControlPanel item returning open command for it.
        /// </summary>
        /// <param name="item">The PowerItem which has to be located/properties for
        /// which have to be shown.</param>
        /// <param name="callerName">String, the name of clicked menu item, hendler
        /// of which is calling this method. Recognizes "AppOpenTargetContainer" and
        /// "AppShowTargetProperties".</param>
        /// <returns>Path to binary FS object that represents the passed PowerItem or
        /// the target of its link.</returns>
        private static string Args4PropsAndCont(PowerItem item, string callerName)
        {
            string arg = null;

            if (item.IsControlPanelChildItem)
            {
                var executor = Util.GetOpenCommandForClass(item.Argument);
                if (executor != null && File.Exists(executor.Item1))
                {
                    arg = executor.Item1;
                }
            }
            if (arg == null)
            {
                arg = PowerItemTree.GetResolvedArgument(item);
            }
            if (item.IsLink && (callerName == "AppOpenTargetContainer" ||
                                callerName == "AppShowTargetProperties"))
            {
                arg = item.ResolvedLink;
            }
            return(arg);
        }
Esempio n. 10
0
 /// <summary>
 /// Handles search event raised by Windows Serach threads.
 /// Works with UI thus invokes Main Dispatcher for real work.
 /// </summary>
 private void HandleSearch(object sender, PowerItemTree.WinSearchEventArgs args)
 {
     Util.Send(() =>
                   {
                       if (args.SearchCompleted)
                       {
                           SearchMarker.Visibility = Visibility.Hidden;
                           ExpandGroup(args.Root, args.Token);
                       }
                       else
                       {
                           SearchMarker.Visibility = Visibility.Visible;
                       }
                   });
 }
Esempio n. 11
0
        //Same as above but inSync
        private static void GetRecentListForSync(PowerItem item)
        {
            string fsObject;

            try
            {
                fsObject = PowerItemTree.GetResolvedArgument(item);
            }
            catch (IOException) //No money no honey (no object to get JL for)
            {
                return;
            }
            IEnumerable <string> jl = null;
            var p8R = GetP8Recent(item.IsLink ? item.ResolvedLink : fsObject); //P8 internal JL

            if (Util.OsIs.SevenOrMore)                                         //System JL
            {
                var recent   = GetJumpList(fsObject, API.ADLT.RECENT);
                var frequent = GetJumpList(fsObject, API.ADLT.FREQUENT);
                if (recent != null && frequent != null)
                {
                    jl = recent.Union(frequent);
                }
                else
                {
                    jl = recent ?? frequent;
                }
            }
            if (jl != null && p8R != null) //merge everything
            {
                jl = jl.Union(p8R);
            }
            else
            {
                jl = jl ?? p8R;
            }
            if (jl == null)
            {
                return;                                            //No jump list discovered -> nothing to do
            }
            jl = jl.Distinct()                                     //No duplicates
                 .Where(x => x.StartsWith("::") || File.Exists(x)) //No obsoletes
                 .Take(25);                                        //Not too many
            foreach (var arg in jl)
            {
                var local = arg;
                Util.Post(() =>
                          item.JumpList.Add(local.StartsWith("::")
                                                ? new PowerItem
                {
                    Argument        = local.Substring(2),
                    Parent          = item,
                    SpecialFolderId = API.Csidl.POWER8JLITEM
                }
                                                : new PowerItem
                {
                    Argument = local,
                    Parent   = item
                }
                                            ));
            }
        }
Esempio n. 12
0
        /// <summary>
        /// This is the part of FriendlyName getter. Executes heavy part of FriendlyName evaluation either
        /// synchronously or in async way, depending on how it's called.
        /// </summary>
        /// <returns>The PI's partially evaluated FriendlyName, which can be also empty string or even null.
        /// Assign the value returned to the FriendlyName. When use this method asynchronously, always Post()
        /// or Send() the assignment.</returns>
        private string TryExtractFriendlyNameAsync()
        {
            string fName = null;

            if (ResourceIdString != null) //Return based on resId
            {
                fName = Util.ResolveStringResource(ResourceIdString);
                if (!string.IsNullOrEmpty(fName))
                {
                    return(fName);
                }
                ResourceIdString = null; //Operation failed somewhere, resourceId is invalid
            }

            if (SpecialFolderId != API.Csidl.INVALID)          //Resolve for a special folder, if any
            {
                if (SpecialFolderId == API.Csidl.POWER8JLITEM) //For jump list item <IShellLink>
                {
                    if (Argument.StartsWith("/n,::"))          //in part., for explorer shell NSs
                    {
                        fName = Util.ResolveLongPathOrDisplayName(Argument.Substring(3));
                    }
                    if (string.IsNullOrEmpty(fName)) //Otherwise, set display name to link target
                    {
                        fName = Argument;
                    }
                    if (!string.IsNullOrEmpty(fName) && fName.Length > 60)
                    { //finally, if it is too long, cut it from the middle
                        fName = fName.Substring(0, 28) +
                                "…" +
                                fName.Substring(fName.Length - 28, 28);
                    }
                }
                else //for all the other special folders
                {
                    fName = Util.ResolveSpecialFolderName(SpecialFolderId);
                }
                if (!string.IsNullOrEmpty(fName))
                {
                    return(fName);
                }
            }

            //If no SpecialFolderId or resolving failed
            if (Parent == null) //main menu
            {                   //this basically should never happen since the moment when desktop.ini parsing is implemented
                return(Resources.Str_AllPrograms);
            }

            //For Recent list...
            if (IsMfuChild) //so it must have ARGUMENT...

            {               //...for either link or exe
                if (IsLink || Argument.EndsWith(".exe", StringComparison.InvariantCultureIgnoreCase))
                {
                    var container = PowerItemTree.SearchStartMenuItemSyncFast(Argument); //yeah, "fast"... :(
                    if (container != null)
                    {
                        fName = container.FriendlyName;
                    }

                    if (string.IsNullOrEmpty(fName) /*(still)*/ && !IsLink)
                    {//get file version info table and extract data from there. Costly but provides valuable results.
                        try
                        {
                            var ver = FileVersionInfo.GetVersionInfo(PowerItemTree.GetResolvedArgument(this));
                            if (!string.IsNullOrWhiteSpace(ver.FileDescription)) //try description, if not fallback to...
                            {
                                fName = ver.FileDescription;
                            }
                            else if (!string.IsNullOrWhiteSpace(ver.ProductName)) //...Product. This is specifically for...
                            {
                                fName = ver.ProductName;                          //...NFS.Run and the kind of.
                            }
                        }
                        catch (IOException) //It is possible that item existing in the last shown list is not available...
                        {} //anymore. This is a rare situation - so try-catch seems more logical than Exists() call.
                    }
                }
                else if (IsControlPanelItemInFact)
                {
                    PowerItemTree.CplDone.WaitOne(); //we don't want InvalidOperationExceptions accessing Items...
                    var same = PowerItemTree.ControlPanelRoot.Items.FirstOrDefault(
                        i => string.Equals(i.Argument, Argument, StringComparison.OrdinalIgnoreCase));
                    if (same != null)              //if there's such item
                    {
                        fName = same.FriendlyName; //simply return it's FriendlyName
                    }
                }
            }
            return(fName);
        }
Esempio n. 13
0
        //------------------------------------------

        /// <summary>
        /// Update Control Panel menu button when ControlPanelByCategoryChanged event occured.
        /// </summary>
        void OnControlPanelByCategoryChanged(object sender, EventArgs e)
        {
            SpecialItems.Remove("ControlPanel");
            PowerItemTree.RefreshControlPanelRoot();
            ControlPanel.Item = GetSpecialItems("ControlPanel");
        }
Esempio n. 14
0
        /// <summary>
        /// Handles specific key presses when focus is in Data grid:
        /// - Enter starts the selected PowerItem, if any;
        /// - Tab/Shift-Tab moves focus to correct controls so that grid doesn't
        /// hold focus inside. There are arrow buttons for that.
        /// </summary>
        private void DataGridPreviewKeyDown(object sender, KeyEventArgs e)
        {
            var pi = dataGrid.SelectedItem as PowerItem;

            switch (e.Key)
            {
            case Key.Enter:
                if (pi != null && !pi.AreItemsDisplayed)
                {
                    e.Handled = true;
                    InvokeFromDataGrid(pi);
                }
                break;

            case Key.Tab:
                e.Handled = true; //todo: check why CTRL is tested differently in other places
                if (pi != null && (Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl)))
                {                 //CTRL+Tab >> put path to item to search bar
                    var t = "\"" + PowerItemTree.GetResolvedTarget(pi) + "\" ";
                    SearchBox.Text = t;
                    SearchBox.Focus();
                    SearchBox.CaretIndex = t.Length;
                }
                else if (Keyboard.IsKeyDown(Key.LeftShift) || Keyboard.IsKeyDown(Key.RightShift))
                {
                    AllItemsMenuRoot.Focus();     //SHIFT+Tab >> focus backwards
                }
                else
                {
                    SearchBox.Focus();     //Tab >> focus forwards
                }
                break;

            case Key.Up:
            case Key.Down:
                if (pi != null && pi.AreItemsDisplayed)
                {
                    return;     //Do not handle keys when JL is in focus
                }
                //Not in search view when we press Up/Down
                if ((System.Windows.Forms.Control.ModifierKeys & Keys.Control) > 0 && dataGrid.ItemsSource.Equals(MfuItems))
                {                                                    //with CTRL
                    if (dataGrid.SelectedIndex > -1 && SettingsManager.Instance.MfuIsCustom)
                    {                                                //...and we have something selected, and we're in custom MFU...
                        var si = dataGrid.SelectedItem as PowerItem; //...and more than 1 in (un) pinned group
                        if (si != null && MfuItems.Count(m => m.IsPinned == si.IsPinned) > 1)
                        {                                            //=> move item itself
                            e.Handled = true;
                            dataGrid.Focus();                        //.Net 4.5 hack. Datagrid in .Net4.5 doesn't switch focus to new row
                            int       increment = (e.Key == Key.Up ? -1 : 1);
                            int       i         = dataGrid.SelectedIndex;
                            PowerItem target    = null;
                            do     //search for nearest item with same pinning state
                            {
                                i += increment;
                                if (i == -1)
                                {
                                    i = MfuItems.Count - 1;
                                }
                                else if (i == MfuItems.Count)
                                {
                                    i = 0;
                                }
                                if (MfuItems[i].IsPinned == si.IsPinned)
                                {
                                    target = MfuItems[i];
                                }
                            } while (target == null);
                            MfuList.MoveCustomListItem(si, target);
                        }
                    }
                }
                else if ((System.Windows.Forms.Control.ModifierKeys & Keys.Control) == 0) //Not with CTRL,
                {                                                                         // regardless of source => just move selection
                    e.Handled = true;
                    var idx = dataGrid.SelectedIndex + (e.Key == Key.Up ? -1 : 1);
                    if (idx < 0)
                    {
                        idx = dataGrid.Items.Count - 1;
                    }
                    if (idx >= dataGrid.Items.Count)
                    {
                        idx = 0;
                    }
                    dataGrid.SelectedIndex = idx;
                }
                if (dataGrid.SelectedItem != null)     //when in search view and no hits/in clear custom list
                {
                    dataGrid.ScrollIntoView(dataGrid.SelectedItem);
                }
                break;

            case Key.P:
                if (pi != null && pi.IsMfuChild)
                {
                    e.Handled    = true;
                    pi.IsPinned ^= true;
                    PinInternal(pi);
                    dataGrid.Focus();
                }
                break;

            case Key.X:
                if (pi != null && dataGrid.ItemsSource.Equals(_searchView))
                {
                    e.Handled = true;
                    ExpandCollapseGroup(pi);
                    dataGrid.Focus();
                }
                break;

            case Key.Right:
            case Key.Left:
                if (pi != null)
                {
                    e.Handled             = true;
                    pi.AreItemsDisplayed ^= true;
                }
                break;
            }
        }