diff --git a/CMakeLists.txt b/CMakeLists.txt index ce290b3..6c6a4aa 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -164,6 +164,7 @@ if(APPLE) MACOSX_BUNDLE_SHORT_VERSION_STRING "${CSV_EXPLORER_VERSION}" MACOSX_BUNDLE_BUNDLE_VERSION "${CSV_EXPLORER_VERSION}" MACOSX_BUNDLE_ICON_FILE "csv-explorer.icns" + MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_SOURCE_DIR}/Info.plist.in" ) set_source_files_properties(${CSV_EXPLORER_BUNDLE_ICON} PROPERTIES MACOSX_PACKAGE_LOCATION Resources) set_source_files_properties(${CSV_EXPLORER_WINDOW_ICON} PROPERTIES MACOSX_PACKAGE_LOCATION Resources) diff --git a/Info.plist.in b/Info.plist.in new file mode 100644 index 0000000..1e1ecfc --- /dev/null +++ b/Info.plist.in @@ -0,0 +1,43 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + ${MACOSX_BUNDLE_EXECUTABLE_NAME} + CFBundleIconFile + ${MACOSX_BUNDLE_ICON_FILE} + CFBundleIdentifier + ${MACOSX_BUNDLE_GUI_IDENTIFIER} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${MACOSX_BUNDLE_BUNDLE_NAME} + CFBundlePackageType + APPL + CFBundleShortVersionString + ${MACOSX_BUNDLE_SHORT_VERSION_STRING} + CFBundleVersion + ${MACOSX_BUNDLE_BUNDLE_VERSION} + CFBundleDocumentTypes + + + CFBundleTypeExtensions + + csv + + CFBundleTypeName + Comma-Separated Values File + CFBundleTypeRole + Editor + LSHandlerRank + Owner + LSItemContentTypes + + public.comma-separated-values-text + + + + + diff --git a/src/main.cpp b/src/main.cpp index 02a0c90..eb44551 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -13,9 +13,21 @@ class CsvExplorerApp : public wxApp { } auto* frame = CreateMainFrame(initialFile); + SetTopWindow(frame); frame->Show(); return true; } + +#ifdef __WXOSX__ + void MacOpenFile(const wxString& fileName) override { + wxFrame* frame = wxDynamicCast(GetTopWindow(), wxFrame); + if (!frame) { + return; + } + + OpenFileInMainFrame(frame, fileName); + } +#endif }; wxIMPLEMENT_APP(CsvExplorerApp); diff --git a/src/main_frame.cpp b/src/main_frame.cpp index 4e3eca8..6262c6e 100644 --- a/src/main_frame.cpp +++ b/src/main_frame.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include #include @@ -133,19 +134,42 @@ class MainFrame : public wxFrame { public: explicit MainFrame(const wxString& initialFile) : wxFrame(nullptr, wxID_ANY, CSV_EXPLORER_NAME, wxDefaultPosition, wxSize(900, 600)) { + SetDropTarget(new CsvFileDropTarget(*this)); BuildMenuBar(); BuildAccelerators(); BuildGrid(); BuildStatusBar(); ApplyWindowIcon(); if (!initialFile.IsEmpty()) { - OpenFile(initialFile); + OpenDocumentFile(initialFile); } else { CreateNewFile(); } } + bool OpenDocumentFile(const wxString& path) { + if (!ConfirmDirtyFileAction()) { + return false; + } + + OpenFile(path); + return !m_currentFile.IsEmpty() && m_currentFile == path; + } + private: + class CsvFileDropTarget final : public wxFileDropTarget { + public: + explicit CsvFileDropTarget(MainFrame& frame) + : m_frame(frame) {} + + bool OnDropFiles(wxCoord, wxCoord, const wxArrayString& filenames) override { + return m_frame.HandleDroppedFiles(filenames); + } + + private: + MainFrame& m_frame; + }; + void BuildMenuBar() { auto* fileMenu = new wxMenu(); fileMenu->Append(wxID_NEW, "&New\tCtrl+N"); @@ -170,9 +194,9 @@ class MainFrame : public wxFrame { editMenu->AppendSeparator(); auto* goToMenu = new wxMenu(); #ifdef __WXOSX__ - goToMenu->Append(ID_GO_TO_FIRST, "Go to &First\tCmd+Up"); - goToMenu->Append(ID_GO_TO_LAST, "Go to &Last\tCmd+Down"); - goToMenu->Append(ID_GO_TO_ROW, "Go to &Row...\tCmd+G"); + goToMenu->Append(ID_GO_TO_FIRST, "Go to &First\tCtrl+Up"); + goToMenu->Append(ID_GO_TO_LAST, "Go to &Last\tCtrl+Down"); + goToMenu->Append(ID_GO_TO_ROW, "Go to &Row...\tCtrl+G"); #else goToMenu->Append(ID_GO_TO_FIRST, "Go to &First\tCtrl+Home"); goToMenu->Append(ID_GO_TO_LAST, "Go to &Last\tCtrl+End"); @@ -214,6 +238,8 @@ class MainFrame : public wxFrame { m_grid->Bind(wxEVT_CHAR_HOOK, &MainFrame::OnGridCharHook, this); m_grid->Bind(wxEVT_SIZE, &MainFrame::OnGridResized, this); m_grid->GetGridWindow()->Bind(wxEVT_LEFT_DCLICK, &MainFrame::OnGridWindowLeftDClick, this); + m_grid->SetDropTarget(new CsvFileDropTarget(*this)); + m_grid->GetGridWindow()->SetDropTarget(new CsvFileDropTarget(*this)); m_headerEditor = new wxTextCtrl( m_grid->GetGridColLabelWindow(), @@ -691,6 +717,14 @@ class MainFrame : public wxFrame { ResizeToCsvContent(); } + bool HandleDroppedFiles(const wxArrayString& filenames) { + if (!IsEffectivelyEmptyDocument() || filenames.empty()) { + return false; + } + + return OpenDocumentFile(filenames[0]); + } + void ResizeToCsvContent() { if (!m_grid || m_rows.empty() || GetColumnCount() == 0) { return; @@ -1349,3 +1383,12 @@ wxEND_EVENT_TABLE() wxFrame* CreateMainFrame(const wxString& initialFile) { return new MainFrame(initialFile); } + +bool OpenFileInMainFrame(wxFrame* frame, const wxString& path) { + auto* mainFrame = dynamic_cast(frame); + if (!mainFrame) { + return false; + } + + return mainFrame->OpenDocumentFile(path); +} diff --git a/src/main_frame.h b/src/main_frame.h index 8a5e368..4bc34ff 100644 --- a/src/main_frame.h +++ b/src/main_frame.h @@ -4,3 +4,4 @@ class wxFrame; class wxString; wxFrame* CreateMainFrame(const wxString& initialFile); +bool OpenFileInMainFrame(wxFrame* frame, const wxString& path);