COM IContextMenu::InvokeCommand - matching LPCMINVOKECOMMANDINFO::lpVerb to item - c++

I have created a shell extension for windows with COM, however I seem to fail to properly match the ids of items I add in the overload of IContextMenu::QueryContextMenu with what I receive in the overload of IContextMenu::InvokeCommand. In my code I use InsertMenu and InsertMenuItem (as far as I understood they do the same, but the latter has some more features?). However I'm not sure which arguments passed to InsertMenu/InsertMenuItem correspond to what I must be looking for in LPCMINVOKECOMMANDINFO::lpVerb. I need some way to easily know that when I add items x, y, z to a context menu, I can then know exactly which one of x, y or z has been clicked.
EDIT: It seems that the verb equals the number from top to bottom of the item in the current menu/submenu. However I have two sub-menus each with x amount of items, so they have the same IDs of 1,2,3. How do I set custom IDs or something?

Firstly you should define an enum that holds the command IDs for your menu items, e.g.
enum {
CMDID_FIRST = 0,
CMDID_DOSOMETHING = CMDID_FIRST,
CMDID_DOSOMETHINGELSE,
CMDID_LAST,
};
These ID values need to start from 0.
In your IContextMenu::QueryContextMenu implementation:
when you add your menu items you need to give each of them an ID by setting the MIIM_ID flag in the MENUITEMINFO.fMask field, and setting the MENUITEMINFO.wID value.
give each of your menu items an ID derived from its command ID as defined above, plus the value of idCmdFirst which is passed into QueryContextMenu. E.g. the "Do Something" menu item would have MENUITEMINFO.wID set to idCmdFirst + CMDID_DOSOMETHING, and "Do Something Else" would have MENUITEMINFO.wID set to idCmdFirst + CMDID_DOSOMETHINGELSE.
the return value from QueryContextMenu needs to be MAKE_HRESULT(SEVERITY_SUCCESS, FACILITY_NULL, x) where x is the ID of the highest-numbered item you added plus 1 (alternatively, if all items were sequentially numbered, the total number of items). Basically, you're telling the host which menu item ID values are now in use so that no other context menu extensions add items that clash with yours. In the above example, you'd return MAKE_HRESULT(SEVERITY_SUCCESS, FACILITY_NULL, CMDID_LAST).
In IContextMenu::InvokeCommand:
test if lpVerb (or lpVerbW) is an integer value using the IS_INTRESOURCE macro.
if so, the command ID can be found in the low word. E.g, if the user selected "Do Something Else", you would find that LOWORD(lpVerb) == CMDID_DOSOMETHINGELSE.

Related

Oracle APEX Compare Two Items Values to Fire a Dynamic Action

I want to create a Dynamic Action thats when my page item P2014_BALANCE < P2014_CURRENT_PRICE then P2014_CURRENT_PRICE gets the static value 0.
The problem is that i can't compare these two page items. I try to when section in my Dynamic Action to use Javascript expression like this:
if(apex.item( "P2014_CURRENT_PRICE " ).getValue() < apex.item( "P2014_CURRENT_PRICE " ).getValue()){
alert('Wrong Number');
};
but when my page loads gets an error (even Fire on Initialization = False).
I also try this:
still nothing.
This is a web application. All page items contain string values. So if you want to do number comparison, make them numbers:
if (Number(apex.item( "P2014_BALANCE" ).getValue()) < Number(apex.item( "P2014_CURRENT_PRICE" ).getValue())) {
alert('Wrong Number');
};
Note that in your example you have P2014_CURRENT_PRICE twice - that will always yield false anyways.
This is how you would implement this in a dynamic action. Note that I tried on 21.1 but it should be similar in 5 (consider upgrading):
Dynamic Action on Change of Item P2014_CURRENT_PRICE with client Side Condition of type Javascript Expression
Source:
apex.locale.toNumber(apex.item( "P2014_CURRENT_PRICE" ).getValue()) > apex.locale.toNumber(apex.item( "P2014_BALANCE" ).getValue())
True Action with Action Set Value
Set Type Static Assignment
Value "0"
Affected Element Item P2014_CURRENT_PRICE

Do not display options in v-autocomplete until there is input vuetify

I currently have a v-autocomplete component but once the user clicks the search it expands and shows all available items. I want the list of items to only display once there is input. There are too many available items and don't want the user seeing all of them right off the bat. Also if there is a way to limit it to only showing the top 5 that match the user input.
<v-autocomplete class="vtext"
v-model="selectedTopic"
:items="getTopics"
item-text="Name"
item-value="Id"
:outlined="false"
:rounded="true"
:solo="true"
:single-line="true"
append-icon='fa fa-search'
#change="topicSelected()"
:hide-no-data="true"
:allow-overflow="false"
no-data-text="No topic found"
return-object
>
</v-autocomplete>
The reason it shows all items on initialization (when clicking empty), is because you are setting the items right away with getTopics what you need to do in that function is check
<v-autocomplete class="vtext"
...
#input="handleInput"
if (inputModel){ //get the topics}
else { return []}
In terms of only getting the first 5 results, again you do it in the same function:
if (inputModel){
// do search
return results.slice(0,5)}

Add empty option to List Validator

I'm trying to add the option to my users that, on a List Validator, to allow select any of the options or a blank option. Spreadjs has the IgnoreBlanks setting, which I use, so when the user uses the delete key or the backspace and deletes the cell it validates correctly.
However, I would love to use the same functionality as in Excel, which allows blank options in the list validator, in part of the list.
I've tried to target the <select> element that holds the list and programmatically add the empty element, however, it crashes after the user selects the empty option.
I've also tried to add different escaped characters to the list. If I select a character that represents an empty string or a tab, it won't add a new option to the list. If I use any strange character, or even the null character \0 you get a new option to select, but the content is that typical rectangle you see when your font doesn't have the character you're trying to display.
I've also tested using a regular ListValidator like in the example pages, not our custom functionality and doesn't work either.
https://www.grapecity.com/demos/spread/JS/TutorialSample/#/demos/basicDataValidator
I have also tried creating a FormulaListValidator, and if my range has empty cells I could then get an empty option on my list, however, because the range may have duplicates, I get duplicated options.
After researching a little bit I found a workaround in a different language which I adapted to Typescript (Angular 6)
export const getListValidatorFromArray = (spread: GC.Spread.Sheets.Workbook, data: any[]) => {
// saving validation list values in a hidden sheet
spread.addSheet(spread.getSheetCount());
const sheet = spread.getSheet(spread.getSheetCount() - 1);
sheet.visible(false);
for (let i = 0; i < data.length; i++) {
sheet.setValue(i, 0, data[i]);
}
// create validator based on the values
const dv = GC.Spread.Sheets.DataValidation.createFormulaListValidator(
'=' + sheet.name() + '!$A$1:' + sheet.name() + '!$A$' + data.length
);
return dv;
};
Note: This creates an extra sheet for each validator you create. Makes sure you reuse them as much as possible (i.e. assigning it to a variable when it's created, and reusing the variable for other columns/rows that use the same one).

AppleScript : keep word only from list

How can I only keep words / numbers from list?
I use the follow script and I want to count unique payment methods, but I have unwanted values on my list
I also tried to use "word of item" but this is not working
I try different version of the script but always having an issue
set PaymentMethods to {}
set UniquePaymentMethods to {}
set walletPayement to {}
set mobilePayemnt to {}
tell application "Safari"
set PaymentMethods to do JavaScript "var outPut=[]; var arr=document.getElementsByClassName('sortable Summary');for (var i in arr) {outPut.push(arr[i].innerHTML)};outPut;" in current tab of window 1
end tell
repeat with x from 1 to count of items of PaymentMethods
set n to item x of PaymentMethods
if n is in PaymentMethods and n is not in UniquePaymentMethods and n does not contain "<a href=\"/finance/Support.ok" and n does not contain "Safari" and n does not contain "None" then set end of UniquePaymentMethods to n
end repeat
e.g of the result :
{"
PayPal
", "
MasterCard (999)
", "
MasterCard (888)
", application "Safari"}
It's good that you're generally mindful about supplying a sample of the input, as you've done here with the list that I presume relates to PaymentMethods. But don't forget to also provide the output you want to get back at the end. It took me a while to realise "keep words / numbers from list" was actually referring to items of class text (or string), which was about my fifth interpretation of what was being asked.
Your solution appears to do what you want, but it doesn't really because you've had to use that very case-specific set of conditionals, i.e.:
if n is in PaymentMethods ¬
and n is not in UniquePaymentMethods ¬
and n does not contain ("<a href=\"/finance/Support.ok") ¬
and n does not contain ("Safari") ¬
and n does not contain "None" then ¬
set end of UniquePaymentMethods to n
Without that, the item application "Safari", for instance, would simply be coerced into class text, which would return "Safari" in your resulting list.
So, while your request was to filter a list's data types to contain only text class items, your proposed fix, i.e.:
set n to item x of PaymentMethods as text
doesn't isolate text items; it coerces items of any class into text.
The way to filter a list by class type is to use this syntax:
get every [class] in [list]
where [class] is the AppleScript class you want to keep (discarding any items not of this class), and [list] is the list (or variable that references a list), e.g.:
every text in {1, "Hello", true, missing value, "2", text, number, pi}
--> {"Hello", "2"}
every number in {1, "Hello", true, missing value, "2", text, number, pi}
--> {1, 3.14159265359}
every application in {"PayPal", "MasterCard (999)", "MasterCard (888)", application "Safari"}
--> {application "Safari"}
every text in {"PayPal", "MasterCard (999)", "MasterCard (888)", application "Safari"}
--> {"PayPal", "MasterCard (999)", "MasterCard (888)"}
But, there's a lot you can do to simplify your script by having the initial JavaScript code do the heavy lifting so it returns a cleaner list of items that will be simpler for AppleScript to process, or eliminate any need for additional processing.
Your list items have a lot of whitespace in them. In JS, use trim().
Your AppleScript conditionals reference "innerHTML property without ever wanting to use any actual HTML. You've been consistently interested only in the text that gets printed on your webpage. Therefore, in JS, experiment with innerText applied to the right HTML element and you'll probably be able to isolate the payment methods text straight away.
You appear to want your list to contain unique items. In JS, use sets, which are basically arrays with unique items.
Implementing these three recommendations, together with the above method of filtering by text class, would look something like:
tell application "Safari" to tell document 1 to tell (do JavaScript "
[...new Set( document.getElementsByClassName('sortable Summary') )]
.map( x => x.innerText.trim() );") ¬
to set PaymentMethods to every text
As I don't know what your webpage source looks like, you may need to make slight adjustments to how you want to transform innerText besides trim(), and/or consider whether getElementsByClassName('sortable Summary') is the best way to get access to the parts of the HTML DOM tree you require. querySelectorAll() is a much more powerful method to use, which I have mentioned before.
Found it, need to add the kind for each item
set n to item x of PaymentMethods as text

1-indexed Model in QCombobox

I have a 1-indexed (readonly-)model and want to use it for a combobox.
I parse the data (comes from a file-parser) and have for example:
1: Variable Number 1 and that will be my first item, next
2: Variable Number 2 and so on.
When I click on an item the currentIndex()-method from QCombobox will give me a 0-indexed int, so my problem is:
I don't want to write everytime I parse a file +1 respectively -1 when writing back to the file (although the model is readonly, I can alter the data in the file). (I have nearly 30 UIs where I need the model, and for every UI I have to parse other data)
I currently use something like:
virtual int currentIndex() const { return QComboBox::currentIndex() + 1; }
virtual void setCurrentIndex(int index) { QComboBox::setCurrentIndex(index-1); }
I know that this is not ideal, because (set-)currentIndex is not virtual. But to avoid +/-1 I used this for now.
Does anybode have a good suggestion for this problem?
If you have a custom model you could add a role that returns the "real" index value.
If you just use strings to fill the combobox, you could use the setItemData() and itemData() methods to associated your reference value.
E.g.
comboBox->addItem("Number 1", 1);
and
int refValue = comboBox->itemData(comboIndex).toInt();
The associated data can be anything that can be stored in a QVariant.