Merge pull request #6809 from Lawrence37/external-editor-macos-fix

Fix external editor on macOS
This commit is contained in:
Lawrence37 2023-08-06 11:54:52 -07:00 committed by GitHub
commit b7816ff882
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 96 additions and 27 deletions

View File

@ -904,6 +904,7 @@ EditorPanel::EditorPanel (FilePanel* filePanel)
send_to_external = Gtk::manage(new PopUpButton("", false));
send_to_external->set_tooltip_text(M("MAIN_BUTTON_SENDTOEDITOR_TOOLTIP"));
send_to_external->setEmptyImage("palette-brush.png");
setExpandAlignProperties(send_to_external->buttonGroup, false, false, Gtk::ALIGN_CENTER, Gtk::ALIGN_FILL);
updateExternalEditorWidget(
options.externalEditorIndex >= 0 ? options.externalEditorIndex : options.externalEditors.size(),
@ -2030,7 +2031,7 @@ bool EditorPanel::idle_saveImage (ProgressConnector<rtengine::IImagefloat*> *pc,
msgd.run ();
saveimgas->set_sensitive (true);
send_to_external->set_sensitive(true);
send_to_external->set_sensitive(send_to_external->getEntryCount());
isProcessing = false;
}
@ -2058,7 +2059,7 @@ bool EditorPanel::idle_imageSaved (ProgressConnector<int> *pc, rtengine::IImagef
}
saveimgas->set_sensitive (true);
send_to_external->set_sensitive(true);
send_to_external->set_sensitive(send_to_external->getEntryCount());
parent->setProgressStr ("");
parent->setProgress (0.);
@ -2249,8 +2250,10 @@ void EditorPanel::sendToExternalPressed()
dialog->show();
} else {
struct ExternalEditor editor = options.externalEditors.at(options.externalEditorIndex);
external_editor_info = Gio::AppInfo::create_from_commandline(editor.command, editor.name, Gio::APP_INFO_CREATE_NONE);
external_editor_native_command = editor.native_command;
external_editor_info = {
editor.name,
editor.command,
editor.native_command};
sendToExternal();
}
}
@ -2388,7 +2391,7 @@ bool EditorPanel::idle_sendToGimp ( ProgressConnector<rtengine::IImagefloat*> *p
Gtk::MessageDialog msgd (*parent, msg_, true, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true);
msgd.run ();
saveimgas->set_sensitive (true);
send_to_external->set_sensitive(true);
send_to_external->set_sensitive(send_to_external->getEntryCount());
}
return false;
@ -2409,14 +2412,14 @@ bool EditorPanel::idle_sentToGimp (ProgressConnector<int> *pc, rtengine::IImagef
if ((!img && Glib::file_test(filename, Glib::FILE_TEST_IS_REGULAR)) || (img && !errore)) {
saveimgas->set_sensitive (true);
send_to_external->set_sensitive(true);
send_to_external->set_sensitive(send_to_external->getEntryCount());
parent->setProgressStr ("");
parent->setProgress (0.);
bool success = false;
setUserOnlyPermission(Gio::File::create_for_path(filename), false);
success = ExtProgStore::openInExternalEditor(filename, external_editor_info, external_editor_native_command);
success = ExtProgStore::openInExternalEditor(filename, external_editor_info);
if (!success) {
Gtk::MessageDialog msgd (*parent, M ("MAIN_MSG_CANNOTSTARTEDITOR"), false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true);
@ -2445,12 +2448,16 @@ RTAppChooserDialog *EditorPanel::getAppChooserDialog()
void EditorPanel::onAppChooserDialogResponse(int responseId)
{
switch (responseId) {
case Gtk::RESPONSE_OK:
case Gtk::RESPONSE_OK: {
getAppChooserDialog()->close();
external_editor_info = getAppChooserDialog()->get_app_info();
external_editor_native_command = false;
const auto app_info = getAppChooserDialog()->get_app_info();
external_editor_info = {
app_info->get_name(),
app_info->get_commandline(),
false};
sendToExternal();
break;
}
case Gtk::RESPONSE_CANCEL:
case Gtk::RESPONSE_CLOSE:
getAppChooserDialog()->close();
@ -2781,7 +2788,10 @@ void EditorPanel::updateExternalEditorWidget(int selectedIndex, const std::vecto
send_to_external->insertEntry(i, "palette-brush.png", name, &send_to_external_radio_group);
}
}
#ifndef __APPLE__
send_to_external->addEntry("palette-brush.png", M("GENERAL_OTHER"), &send_to_external_radio_group);
#endif
send_to_external->set_sensitive(send_to_external->getEntryCount());
send_to_external->setSelected(selectedIndex);
send_to_external->show();
}

View File

@ -21,6 +21,7 @@
#include <gtkmm.h>
#include "extprog.h"
#include "histogrampanel.h"
#include "history.h"
#include "imageareapanel.h"
@ -252,8 +253,7 @@ private:
Gtk::Button* navSync;
Gtk::Button* navNext;
Gtk::Button* navPrev;
Glib::RefPtr<Gio::AppInfo> external_editor_info;
bool external_editor_native_command;
EditorInfo external_editor_info;
std::unique_ptr<RTAppChooserDialog> app_chooser_dialog;
ExternalEditorChangedSignal *externalEditorChangedSignal;
sigc::connection externalEditorChangedSignalConnection;

View File

@ -37,7 +37,9 @@ ExternalEditorPreferences::ExternalEditorPreferences():
list_view = Gtk::manage(new Gtk::TreeView());
list_view->set_model(list_model);
list_view->append_column(*Gtk::manage(makeAppColumn()));
#ifndef __APPLE__
list_view->append_column(*Gtk::manage(makeNativeCommandColumn()));
#endif
list_view->append_column(*Gtk::manage(makeCommandColumn()));
for (auto &&column : list_view->get_columns()) {
@ -59,11 +61,18 @@ ExternalEditorPreferences::ExternalEditorPreferences():
button_remove = Gtk::manage(new Gtk::Button());
button_add->set_image(*add_image);
button_remove->set_image(*remove_image);
button_app_chooser = Gtk::manage(new Gtk::Button(M("PREFERENCES_EXTERNALEDITOR_CHANGE")));
button_app_chooser =
#ifdef __APPLE__
nullptr;
#else
Gtk::manage(new Gtk::Button(M("PREFERENCES_EXTERNALEDITOR_CHANGE")));
#endif
button_file_chooser = Gtk::manage(new Gtk::Button(M("PREFERENCES_EXTERNALEDITOR_CHANGE_FILE")));
button_app_chooser->signal_pressed().connect(sigc::mem_fun(
*this, &ExternalEditorPreferences::openAppChooserDialog));
if (button_app_chooser) {
button_app_chooser->signal_pressed().connect(sigc::mem_fun(
*this, &ExternalEditorPreferences::openAppChooserDialog));
}
button_add->signal_pressed().connect(sigc::mem_fun(
*this, &ExternalEditorPreferences::addEditor));
button_file_chooser->signal_pressed().connect(sigc::mem_fun(
@ -77,7 +86,9 @@ ExternalEditorPreferences::ExternalEditorPreferences():
// Toolbar.
toolbar.set_halign(Gtk::Align::ALIGN_END);
toolbar.add(*button_app_chooser);
if (button_app_chooser) {
toolbar.add(*button_app_chooser);
}
toolbar.add(*button_file_chooser);
toolbar.add(*button_add);
toolbar.add(*button_remove);
@ -156,6 +167,9 @@ void ExternalEditorPreferences::addEditor()
}
row[model_columns.name] = "-";
#ifdef __APPLE__
row[model_columns.native_command] = true;
#endif
list_view->get_selection()->select(row);
}
@ -244,7 +258,12 @@ void ExternalEditorPreferences::onFileChooserDialogResponse(
for (const auto &selected : selection) {
auto row = *list_model->get_iter(selected);
row[model_columns.icon] = Glib::RefPtr<Gio::Icon>(nullptr);
row[model_columns.native_command] = false;
row[model_columns.native_command] =
#ifdef __APPLE__
true;
#else
false;
#endif
row[model_columns.command] =
#ifdef WIN32
'"' + dialog->get_filename() + '"';
@ -360,7 +379,9 @@ void ExternalEditorPreferences::setAppName(
void ExternalEditorPreferences::updateToolbarSensitivity()
{
bool selected = list_view->get_selection()->count_selected_rows();
button_app_chooser->set_sensitive(selected);
if (button_app_chooser) {
button_app_chooser->set_sensitive(selected);
}
button_file_chooser->set_sensitive(selected);
button_remove->set_sensitive(selected);
}

View File

@ -344,13 +344,13 @@ bool ExtProgStore::openInCustomEditor (const Glib::ustring& fileName, const Glib
}
bool ExtProgStore::openInExternalEditor(const Glib::ustring &fileName, const Glib::RefPtr<Gio::AppInfo> &editorInfo, bool nativeCommand)
bool ExtProgStore::openInExternalEditor(const Glib::ustring &fileName, const EditorInfo &editorInfo)
{
if (nativeCommand) {
if (editorInfo.isNativeCommand) {
if (rtengine::settings->verbose) {
std::cout << "Launching external editor as native command." << std::endl;
}
const Glib::ustring command = editorInfo->get_commandline();
const Glib::ustring command = editorInfo.commandline;
return openInCustomEditor(fileName, &command);
}
@ -361,7 +361,10 @@ bool ExtProgStore::openInExternalEditor(const Glib::ustring &fileName, const Gli
bool success = false;
try {
success = editorInfo->launch(Gio::File::create_for_path(fileName));
Glib::RefPtr<Gio::AppInfo> appInfo =
Gio::AppInfo::create_from_commandline(
editorInfo.commandline, editorInfo.name, Gio::APP_INFO_CREATE_NONE);
success = appInfo->launch(Gio::File::create_for_path(fileName));
} catch (const Glib::Error &e) {
std::cerr
<< "Error launching external editor.\n"
@ -377,7 +380,7 @@ bool ExtProgStore::openInExternalEditor(const Glib::ustring &fileName, const Gli
if (rtengine::settings->verbose) {
std::cout << "Unable to launch external editor with Gio. Trying custom launcher." << std::endl;
}
Glib::ustring command = editorInfo->get_commandline();
Glib::ustring command = editorInfo.commandline;
#if defined WIN32
if (command.length() > 2 && command[0] == '"' && command[command.length() - 1] == '"') {
command = command.substr(1, command.length() - 2);

View File

@ -42,6 +42,13 @@ struct ExtProgAction
bool execute (const std::vector<Glib::ustring>& fileNames) const;
};
struct EditorInfo
{
Glib::ustring name;
Glib::ustring commandline;
bool isNativeCommand;
};
// Stores all external programs that could be called by the user
class ExtProgStore
{
@ -70,7 +77,7 @@ public:
static bool openInGimp (const Glib::ustring& fileName);
static bool openInPhotoshop (const Glib::ustring& fileName);
static bool openInCustomEditor (const Glib::ustring& fileName, const Glib::ustring* command = nullptr);
static bool openInExternalEditor(const Glib::ustring &fileName, const Glib::RefPtr<Gio::AppInfo> &editorInfo, bool nativeCommand);
static bool openInExternalEditor(const Glib::ustring &fileName, const EditorInfo &editorInfo);
};
#define extProgStore ExtProgStore::getInstance()

View File

@ -136,6 +136,21 @@ bool PopUpCommon::insertEntryImpl(int position, const Glib::ustring& fileName, c
return true;
}
void PopUpCommon::setEmptyImage(const Glib::ustring &fileName)
{
emptyImageFilename = fileName;
if (getEntryCount()) {
return;
}
if (fileName.empty()) {
buttonImage->hide();
} else {
changeImage(emptyImageFilename, Glib::RefPtr<const Gio::Icon>());
buttonImage->show();
}
}
void PopUpCommon::removeEntry(int position)
{
if (position < 0 || position >= getEntryCount()) {
@ -147,8 +162,13 @@ void PopUpCommon::removeEntry(int position)
button->get_style_context()->remove_class("Left");
arrowButton->hide();
hasMenu = false;
// Remove the button image.
buttonImage->hide();
if (emptyImageFilename.empty()) {
// Remove the button image.
buttonImage->hide();
} else {
// Show the empty icon.
changeImage(emptyImageFilename, Glib::RefPtr<const Gio::Icon>());
}
selected = -1;
}
else if (position < selected) {

View File

@ -64,6 +64,8 @@ public:
bool addEntry (const Glib::ustring& fileName, const Glib::ustring& label, Gtk::RadioButtonGroup* radioGroup = nullptr);
bool insertEntry(int position, const Glib::ustring& fileName, const Glib::ustring& label, Gtk::RadioButtonGroup* radioGroup = nullptr);
bool insertEntry(int position, const Glib::RefPtr<const Gio::Icon>& gIcon, const Glib::ustring& label, Gtk::RadioButtonGroup* radioGroup = nullptr);
/// Sets the button image to show when there are no entries.
void setEmptyImage(const Glib::ustring &fileName);
int getEntryCount () const;
bool setSelected (int entryNum);
int getSelected () const;
@ -77,6 +79,7 @@ private:
type_signal_changed messageChanged;
type_signal_item_selected messageItemSelected;
Glib::ustring emptyImageFilename;
std::vector<Glib::RefPtr<const Gio::Icon>> imageIcons;
std::vector<Glib::ustring> imageFilenames;
std::vector<const RTImage*> images;

View File

@ -1772,7 +1772,12 @@ void Preferences::storePreferences()
const std::vector<ExternalEditorPreferences::EditorInfo> &editors = externalEditors->getEditors();
moptions.externalEditors.resize(editors.size());
moptions.externalEditorIndex = -1;
moptions.externalEditorIndex =
#ifdef __APPLE__
editors.empty() ? -1 : 0;
#else
-1;
#endif
for (unsigned i = 0; i < editors.size(); i++) {
moptions.externalEditors[i] = (ExternalEditor(
editors[i].name, editors[i].command, editors[i].native_command, editors[i].icon_serialized));