The presenter and the view are both part of the presentation layer. So, while the presenter doesn't know anything about the GUI framework, it does know about presentation logic, and presentation-related concepts. It just doesn't express them in GUI framework–specific way. E.g., you could have a method on it that returns actions available for an item, encoded as data, and have the view (or some view-aware helper function/class) convert those actions into GUI controls. Heck, you could even have a method on it that returns a different presenter for a subview (without knowing what the view actually is - it's just designed to have such a method, in order to support presentation logic as conceptualized at a high level).
Such methods and data structures are what forms the presenter abstraction as seen from the view side. When people hear "abstraction", their mind usually jumps to "abstract class", but here it's used in this more fundamental sense. Basically, think of it like this: if you're determined to avoid any mention of GUI framework–specific names, what data structures and functions you need to come up with to be able to express the essential features of the presentation logic when writing the presenter? Or perhaps: if you expect a lot of fiddling with the details of the view (color-coding, kinds of controls for certain actions, layout, ...), how can you express what these things are about in a way that's relatively resilient to these changes? E.g. a simple example of that is, instead of having an enum { Green, Yellow, Red }
, you use { OK, Warning, Error }
. The end product of this process is what constitutes your abstraction: the functions, data structures and interfaces at the view-facing boundary.
So, for the situation you're describing, a way to do it would be:
- The view receives the "open context menu" event for a list item
- The view (directly or through some mechanism) invokes a "get actions for [item]" method on the presenter. In this case, it's probably best if the view can obtain the return value of this method, rather than wait for the presenter to subsequently push the result into the view by some other mechanism (that's possible too, but likely more convoluted; e.g., you could pass a lambda as the second parameter and have the presenter call it).
- The presenter calls something that knows how to produce a list of actions (or something describing the actions) given the current item, then passes the result along (perhaps after embellishing it with some additional presentation-related data).
- The view converts these actions into controls (context menu items), or calls something that can do the conversion for it, or relies on some framework mechanism that can, say, instantiate a template, or whatever.
- The context menu is shown.
E.g., you could do this within a slot that's connected to the customContextMenuRequested signal.
But don't stop there. I said that this is "a way to do it" on purpose. Explore a couple of other options, perhaps even some that are a bit out there, all the while keeping YAGNI in mind. The goal now is not to predict some future change, but to attempt to get a fresh perspective on the problem.
For example, suppose that, since there are only a couple of possible actions (bear with me if that's not actually the case), your users ask you to replace the context menu with a set of small buttons (some enabled, some disabled), shown inline with the list item, so that they can save a click. Assuming that it's cheap to determine the available actions, in this case it makes sense to get them together with the items, when first populating the list box. Maybe that's a better abstraction. Perhaps that will let you do things like live update of available actions, in case the state of the selected item can be changed in a different view that's simultaneously visible.
OK, now come back to your current implementation that is based around a context menu. Perhaps it makes sense to do this anyway. Perhaps you can calculate all that you need up front, eliminating the need to call the presenter in this case. Nobody can tell you what's the best option here - you get to decide based on your understanding of the domain. You get to decide if this is something worth pursuing or if you should apply YAGNI. Another thing to take into account is which of the approaches you've considered offers least friction with the language and the framework, while retaining a good amount of design benefits that you're after - because, while you can, in principle, ignore the framework in code, there are practical concerns that mean that you can't really ignore all aspects of it (to various degrees).
Now, the problem is, the views tend to be very fiddly (they tend to be tweaked a lot, especially in the beginning), so it's hard to come up with these abstractions and have them be reasonably stable. Also, people tend to make presenters (and classes in general) too big, responsible for too many things, and thus they hardcode a lot of wrong assumptions into them; this leads to a lot of accidental internal coupling. But then parts of these presenters need to change in different ways, at different rates, for different reasons, and this accidental coupling makes changing things tedious. So one thing that helps is: think smaller, and distribute responsibilities. There doesn't have to be a single presenter - you can have a number of collaborating classes; adjust the pattern to suit your specific problem better.
Also, GUI frameworks and control libraries help in some ways (e.g., they might provide a databinding mechanism, eliminating some boilerplate), but they can also bring in some constraints (e.g., they might be geared more towards getting things up and running quickly for a certain set of scenarios, but can get in your way if you try to do something outside of that, or they might impose a certain style of programming). So you have to find a balance between designing for your needs and not working against the framework too much.
"Lets say I have a GUI application which tries to adhere to
Model-View-Presenter (MVP) as best as possible."
I know that when you don't yet have a deep understanding of a concepts, it's helpful to follow a set of rules, but this is bit of a double-edged sword. There are several variations of the MVP pattern; I'm mentioning this to show you that people have been adjusting the pattern to better suit their specific needs or to work better with the language and the framework they use. So don't be afraid to introduce your own tweaks if you need to.