Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 38 additions & 3 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
cmake_minimum_required(VERSION 3.24)

project(CSVExplorer VERSION 0.4.0 LANGUAGES CXX)
project(CSVExplorer VERSION 0.4.0 LANGUAGES C CXX)

if(APPLE)
set(CMAKE_OSX_ARCHITECTURES "arm64;x86_64" CACHE STRING "Build universal macOS binaries" FORCE)
Expand All @@ -15,6 +15,8 @@ set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)

include(FetchContent)

find_package(Git QUIET)
set(CSV_EXPLORER_GIT_COMMIT_SHORT "unknown")
if(GIT_FOUND)
Expand Down Expand Up @@ -72,6 +74,7 @@ add_executable(csv_explorer
src/main.cpp
src/main_frame.cpp
src/print_support.cpp
src/sqlite_import_dialog.cpp
src/unsaved_changes_dialog.cpp
)

Expand All @@ -92,6 +95,40 @@ target_include_directories(csv_explorer
${CMAKE_CURRENT_BINARY_DIR}
)

set(SQLITE_AMALGAMATION_VERSION 3510300)
set(SQLITE_VERSION 3.51.3)
set(SQLITE_DOWNLOAD_YEAR 2026)
FetchContent_Declare(
sqlite
URL https://sqlite.org/${SQLITE_DOWNLOAD_YEAR}/sqlite-amalgamation-${SQLITE_AMALGAMATION_VERSION}.zip
)
FetchContent_GetProperties(sqlite)
if(NOT sqlite_POPULATED)
cmake_policy(PUSH)
if(POLICY CMP0169)
cmake_policy(SET CMP0169 OLD)
endif()
FetchContent_Populate(sqlite)
cmake_policy(POP)
endif()

add_library(sqlite3 STATIC
${sqlite_SOURCE_DIR}/sqlite3.c
)
add_library(SQLite::SQLite3 ALIAS sqlite3)
set_target_properties(sqlite3 PROPERTIES
OUTPUT_NAME sqlite3
)
target_include_directories(sqlite3
PUBLIC
${sqlite_SOURCE_DIR}
)
target_compile_definitions(sqlite3
PRIVATE
SQLITE_OMIT_LOAD_EXTENSION
)
target_link_libraries(csv_explorer PRIVATE SQLite::SQLite3)

set(CSV_EXPLORER_MINGW_CROSS FALSE)
if(CMAKE_CROSSCOMPILING
AND CMAKE_SYSTEM_NAME STREQUAL "Windows"
Expand All @@ -100,8 +137,6 @@ if(CMAKE_CROSSCOMPILING
endif()

if(CMAKE_SYSTEM_NAME STREQUAL "Windows" OR APPLE)
include(FetchContent)

if(CMAKE_VERSION VERSION_GREATER_EQUAL "4.0")
set(CMAKE_POLICY_VERSION_MINIMUM "3.5")
endif()
Expand Down
88 changes: 88 additions & 0 deletions src/main_frame.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include "go_to_row_dialog.h"
#include "main_frame.h"
#include "print_support.h"
#include "sqlite_import_dialog.h"
#include "unsaved_changes_dialog.h"

namespace {
Expand All @@ -33,6 +34,8 @@ enum {
ID_GO_TO_FIRST,
ID_GO_TO_LAST,
ID_GO_TO_ROW,
ID_IMPORT_SQLITE,
ID_EXPORT_SQLITE,
ID_CONTEXT_COPY_ROW,
ID_CONTEXT_COPY_CELL,
ID_INSERT_ROW_BEFORE,
Expand Down Expand Up @@ -179,13 +182,16 @@ class MainFrame : public wxFrame {
bool ConfirmCloseAllPages();
bool ClosePage(EditorPage* page);
EditorPage* CreateBlankTab(bool activate, bool startEditingHeader);
bool ImportTableInPreferredPage(EditorPage* preferredPage, const ImportedSqliteTable& importedTable);
bool OpenPathInPreferredPage(EditorPage* preferredPage, const wxString& path);

void OnNewWindow(wxCommandEvent&);
void OnNewTab(wxCommandEvent&);
void OnCloseWindow(wxCommandEvent&);
void OnCloseTab(wxCommandEvent&);
void OnOpen(wxCommandEvent&);
void OnImportFromSqlite(wxCommandEvent&);
void OnExportToSqlite(wxCommandEvent&);
void OnSave(wxCommandEvent&);
void OnSaveAs(wxCommandEvent&);
void OnPrintPreview(wxCommandEvent&);
Expand Down Expand Up @@ -220,6 +226,7 @@ class EditorPage : public wxPanel {
bool SaveCurrentFileAs();
bool ConfirmClose();
void CreateBlankDocument(bool startEditingHeader);
void LoadImportedTable(const ImportedSqliteTable& importedTable);
bool IsEffectivelyEmptyDocument() const;
bool IsDirty() const {
return m_isDirty;
Expand Down Expand Up @@ -381,6 +388,12 @@ void MainFrame::BuildMenuBar() {
auto* fileMenu = new wxMenu();
fileMenu->Append(wxID_NEW, "&New...\tCtrl+N");
fileMenu->Append(wxID_OPEN, "&Open...\tCtrl+O");
auto* importMenu = new wxMenu();
importMenu->Append(ID_IMPORT_SQLITE, "From &SQLite Database...");
fileMenu->AppendSubMenu(importMenu, "&Import");
auto* exportMenu = new wxMenu();
exportMenu->Append(ID_EXPORT_SQLITE, "To S&QLite Database...");
fileMenu->AppendSubMenu(exportMenu, "E&xport");
fileMenu->AppendSeparator();
fileMenu->Append(wxID_SAVE, "&Save\tCtrl+S");
fileMenu->Append(wxID_SAVEAS, "Save &As...\tCtrl+Shift+S");
Expand Down Expand Up @@ -485,6 +498,8 @@ void MainFrame::BuildNotebook() {
Bind(wxEVT_MENU, &MainFrame::OnCloseWindow, this, ID_CLOSE_WINDOW);
Bind(wxEVT_MENU, &MainFrame::OnCloseTab, this, ID_CLOSE_TAB);
Bind(wxEVT_MENU, &MainFrame::OnOpen, this, wxID_OPEN);
Bind(wxEVT_MENU, &MainFrame::OnImportFromSqlite, this, ID_IMPORT_SQLITE);
Bind(wxEVT_MENU, &MainFrame::OnExportToSqlite, this, ID_EXPORT_SQLITE);
Bind(wxEVT_MENU, &MainFrame::OnSave, this, wxID_SAVE);
Bind(wxEVT_MENU, &MainFrame::OnSaveAs, this, wxID_SAVEAS);
Bind(wxEVT_MENU, &MainFrame::OnPrintPreview, this, wxID_PREVIEW);
Expand Down Expand Up @@ -607,6 +622,29 @@ bool MainFrame::OpenPathInPreferredPage(EditorPage* preferredPage, const wxStrin
return true;
}

bool MainFrame::ImportTableInPreferredPage(EditorPage* preferredPage, const ImportedSqliteTable& importedTable) {
if (preferredPage && preferredPage->IsEffectivelyEmptyDocument()) {
const int pageIndex = m_notebook ? m_notebook->FindPage(preferredPage) : wxNOT_FOUND;
if (m_notebook && pageIndex != wxNOT_FOUND) {
m_notebook->SetSelection(static_cast<size_t>(pageIndex));
}
preferredPage->LoadImportedTable(importedTable);
return true;
}

MainFrame* frame = CreateAndShowMainFrame({});
if (!frame) {
return false;
}

if (EditorPage* page = frame->GetActivePage()) {
page->LoadImportedTable(importedTable);
return true;
}

return false;
}

bool MainFrame::OpenDocumentPath(const wxString& path) {
return OpenPathInPreferredPage(GetActivePage(), path);
}
Expand Down Expand Up @@ -703,6 +741,30 @@ void MainFrame::OnOpen(wxCommandEvent&) {
}
}

void MainFrame::OnImportFromSqlite(wxCommandEvent&) {
ImportedSqliteTable importedTable;
if (!ShowSqliteImportDialog(this, &importedTable)) {
return;
}

ImportTableInPreferredPage(GetActivePage(), importedTable);
}

void MainFrame::OnExportToSqlite(wxCommandEvent&) {
EditorPage* page = GetActivePage();
if (!page) {
return;
}

PrintableDocument document = page->BuildPrintableDocument();
ImportedSqliteTable exportedTable;
exportedTable.documentName = document.title;
exportedTable.headers = document.headers;
exportedTable.rows = document.rows;

ShowSqliteExportDialog(this, exportedTable);
}

void MainFrame::OnSave(wxCommandEvent&) {
if (EditorPage* page = GetActivePage()) {
page->SaveCurrentFile();
Expand Down Expand Up @@ -1289,6 +1351,32 @@ void EditorPage::CreateBlankDocument(bool startEditingHeader) {
}
}

void EditorPage::LoadImportedTable(const ImportedSqliteTable& importedTable) {
CancelHeaderEdit();
CommitActiveEdit();

m_headers = importedTable.headers;
m_rows = importedTable.rows;
NormalizeRows(static_cast<unsigned int>(m_headers.size()));
RefreshGridFromData();
m_grid->ClearSelection();

m_currentFile.clear();
m_documentName = importedTable.documentName.IsEmpty() ? "untitled.csv" : importedTable.documentName;
m_lastFindValid = false;
m_lastFindIndex = 0;
m_contextRow = -1;
m_contextColumn = -1;
m_isDirty = true;
NotifyStateChanged();

if (m_grid->GetNumberRows() > 0 && m_grid->GetNumberCols() > 0) {
SelectCell(0, 0);
} else {
FocusEditor();
}
}

void EditorPage::OpenFileInternal(const wxString& path) {
CancelHeaderEdit();

Expand Down
Loading
Loading