Adding actions to the Project view's toolbar


Hello there, 

I'm making a plugin that adds functionality to the Project view and I'd like to add actions to its tool window's toolbar.

I'm aware of:




However these simply replace all existing actions with new ones. I obviously don't want to remove the default ones (since it's an existing ToolWindow), and there doesn't seem to be any method to either add or at least retrieve the list of actions :(

I'm afraid this isn't possible (which is a shame) but if you know of a way, I'd be glad to hear it.



So after asking the same question on Gitter (thanks to @Wicpar and @krasa), it seems like the only solution would be to use Java Reflection to access the non-public properties. Even though that's obviously super ugly.

Here's the code I'm using right now (which also caches retrieved values):

* Holds cached results from {@link ThisClass#getRestrictedFieldValue(Object, Class, Class)}
private final Map<RestrictedFieldValueCacheEntry, Object> restrictedFieldValuesCache = new HashMap<>();

* Accesses a field using reflection. To be used with caution, only in exceptional cases.
* The field is accessed using its type, so it will only work reliably if declaringClass has only one field of this type.
* The reason it's not using field names is because some SDK's JAR files have obfustated field/method names.
* @param declaringClass The class which contains the field.
* @param object The object whose field to access.
* @param fieldClass The class of the field.
* @return The value of the field.
* @throws NoSuchFieldException Thrown if the field does not exist in the given class.
* @throws IllegalAccessException Thrown if the field still cannot be accessed.
Object getRestrictedFieldValue(@NotNull Object object, @NotNull Class declaringClass, @NotNull Class<?> fieldClass) throws NoSuchFieldException, IllegalAccessException {
RestrictedFieldValueCacheEntry cacheKey = new RestrictedFieldValueCacheEntry(object, declaringClass, fieldClass);

if (!restrictedFieldValuesCache.containsKey(cacheKey)) {
Optional<Field> fieldOptional = -> fieldClass.isAssignableFrom(field.getType())).findFirst();
if (!fieldOptional.isPresent()) {
throw new NoSuchFieldException("Could not find any field of type " + fieldClass.getName() + " in class " + declaringClass.getName());
Field field = fieldOptional.get();
restrictedFieldValuesCache.put(cacheKey, field.get(object));

return restrictedFieldValuesCache.get(cacheKey);

* Represents an unique cache key for {@link ThisClass#restrictedFieldValuesCache}
private class RestrictedFieldValueCacheEntry {
final Object object;
final Class declaringClass;
final Class fieldClass;

public RestrictedFieldValueCacheEntry(Object object, Class declaringClass, Class fieldClass) {
this.object = object;
this.declaringClass = declaringClass;
this.fieldClass = fieldClass;

public boolean equals(Object other) {
if (!(other instanceof RestrictedFieldValueCacheEntry)) {
return false;
RestrictedFieldValueCacheEntry otherEntry = (RestrictedFieldValueCacheEntry)other;
return object == otherEntry.object && declaringClass == otherEntry.declaringClass && fieldClass == otherEntry.fieldClass;

public int hashCode() {
return Objects.hash(object, declaringClass, fieldClass);

You then access project view's tool window > decorator > header > action group using this.

To get the ToolWindow:


If anyone has a better solution, feel free to share it.

Permanently deleted user

Hi Jeto,

Reflection is a bad practice. You can use it, but I recommend to file a feature request for needed API.


Hello Sergey, 

Of course, you're completely right, I realize it's ugly and should be avoided. I do plan to submit a feature request (as I mentioned on Gitter).


Please sign in to leave a comment.