1414#include < QComboBox>
1515#include < QLineEdit>
1616#include < QPushButton>
17+ #include < QItemSelectionModel>
1718
1819#include " excelitemdelegate.h"
1920
@@ -36,13 +37,13 @@ MainWindow::~MainWindow() = default;
3637
3738void MainWindow::setup_ui ()
3839{
39- // Central widget: top bar ( sheet controls) + table view
40+ // central widget: top sheet bar + table view
4041 QWidget *central = new QWidget (this );
4142 QVBoxLayout *v_layout = new QVBoxLayout (central);
4243 v_layout->setContentsMargins (4 , 4 , 4 , 4 );
4344 v_layout->setSpacing (4 );
4445
45- // Top bar: sheet selection + rename + new/delete/move
46+ // top sheet bar: sheet selection + rename + new/delete/move + row/column insertion
4647 QWidget *sheet_bar = new QWidget (central);
4748 QHBoxLayout *h_layout = new QHBoxLayout (sheet_bar);
4849 h_layout->setContentsMargins (0 , 0 , 0 , 0 );
@@ -61,6 +62,10 @@ void MainWindow::setup_ui()
6162 sheet_move_left_button_ = new QPushButton (tr (" ◀" ), sheet_bar);
6263 sheet_move_right_button_ = new QPushButton (tr (" ▶" ), sheet_bar);
6364
65+ // row / column insertion buttons
66+ add_row_button_ = new QPushButton (tr (" +Row" ), sheet_bar);
67+ add_column_button_ = new QPushButton (tr (" +Col" ), sheet_bar);
68+
6469 h_layout->addWidget (sheet_label);
6570 h_layout->addWidget (sheet_combo_, 0 );
6671 h_layout->addSpacing (8 );
@@ -73,9 +78,14 @@ void MainWindow::setup_ui()
7378 h_layout->addWidget (sheet_move_left_button_);
7479 h_layout->addWidget (sheet_move_right_button_);
7580
81+ h_layout->addSpacing (12 );
82+ h_layout->addWidget (new QLabel (tr (" Insert:" ), sheet_bar));
83+ h_layout->addWidget (add_row_button_);
84+ h_layout->addWidget (add_column_button_);
85+
7686 v_layout->addWidget (sheet_bar);
7787
78- // Table view
88+ // table view
7989 table_view_ = new QTableView (central);
8090 table_view_->setAlternatingRowColors (true );
8191 table_view_->setSelectionBehavior (QAbstractItemView::SelectItems);
@@ -87,13 +97,13 @@ void MainWindow::setup_ui()
8797
8898 setCentralWidget (central);
8999
90- // Delegate
100+ // delegate
91101 delegate_ = new ExcelItemDelegate (this );
92102 table_view_->setItemDelegate (delegate_);
93103
94104 statusBar ()->showMessage (tr (" Ready" ));
95105
96- // Connections
106+ // connections
97107 connect (sheet_combo_, QOverload<int >::of (&QComboBox::currentIndexChanged),
98108 this , &MainWindow::on_current_sheet_changed);
99109 connect (sheet_rename_button_, &QPushButton::clicked,
@@ -106,6 +116,12 @@ void MainWindow::setup_ui()
106116 this , &MainWindow::on_sheet_move_left_button_clicked);
107117 connect (sheet_move_right_button_, &QPushButton::clicked,
108118 this , &MainWindow::on_sheet_move_right_button_clicked);
119+
120+ // row / column insertion buttons
121+ connect (add_row_button_, &QPushButton::clicked,
122+ this , &MainWindow::on_add_row_button_clicked);
123+ connect (add_column_button_, &QPushButton::clicked,
124+ this , &MainWindow::on_add_column_button_clicked);
109125}
110126
111127void MainWindow::setup_menu ()
@@ -127,9 +143,7 @@ void MainWindow::setup_menu()
127143 file_menu->addSeparator ();
128144 file_menu->addAction (action_exit_);
129145
130- // ---------------------------------------------------------
131- // ★ Help 메뉴 추가
132- // ---------------------------------------------------------
146+ // Help menu
133147 QMenu *help_menu = menuBar ()->addMenu (tr (" &Help" ));
134148 QAction *action_about = new QAction (tr (" &About ExcelTableEditor" ), this );
135149 help_menu->addAction (action_about);
@@ -270,7 +284,7 @@ void MainWindow::on_model_data_changed()
270284 is_modified_ = true ;
271285}
272286
273- // Sheet combo box changed
287+ // sheet combobox change handler
274288void MainWindow::on_current_sheet_changed (int index)
275289{
276290 if (index < 0 || index >= sheet_names_.size ()) {
@@ -281,7 +295,7 @@ void MainWindow::on_current_sheet_changed(int index)
281295 set_current_sheet (sheet_name);
282296}
283297
284- // Rename current sheet
298+ // rename current sheet
285299void MainWindow::on_sheet_rename_button_clicked ()
286300{
287301 if (current_sheet_name_.isEmpty ()) {
@@ -305,10 +319,10 @@ void MainWindow::on_sheet_rename_button_clicked()
305319 return ;
306320 }
307321
308- // Update sheet name list
322+ // update sheet name list
309323 sheet_names_[idx] = new_name;
310324
311- // Update keys in maps
325+ // change map key
312326 auto model = sheet_models_.take (current_sheet_name_);
313327 auto formats = sheet_formats_.take (current_sheet_name_);
314328 sheet_models_.insert (new_name, model);
@@ -322,13 +336,12 @@ void MainWindow::on_sheet_rename_button_clicked()
322336 statusBar ()->showMessage (tr (" Sheet renamed to: %1" ).arg (new_name), 3000 );
323337}
324338
325- // Create new sheet
339+ // create new sheet
326340void MainWindow::on_sheet_new_button_clicked ()
327341{
328342 const QString new_name = generate_unique_sheet_name ();
329343
330344 auto *model = new QStandardItemModel (this );
331- // Small default grid
332345 const int default_rows = 10 ;
333346 const int default_cols = 5 ;
334347 model->setRowCount (default_rows);
@@ -352,7 +365,7 @@ void MainWindow::on_sheet_new_button_clicked()
352365 statusBar ()->showMessage (tr (" New sheet created: %1" ).arg (new_name), 3000 );
353366}
354367
355- // Delete current sheet
368+ // delete current sheet
356369void MainWindow::on_sheet_delete_button_clicked ()
357370{
358371 if (current_sheet_name_.isEmpty ()) {
@@ -390,7 +403,6 @@ void MainWindow::on_sheet_delete_button_clicked()
390403 sheet_formats_.remove (removed_name);
391404 sheet_names_.removeAt (idx);
392405
393- // Determine new current sheet index
394406 int new_idx = idx;
395407 if (new_idx >= sheet_names_.size ()) {
396408 new_idx = sheet_names_.size () - 1 ;
@@ -415,7 +427,7 @@ void MainWindow::on_sheet_delete_button_clicked()
415427 statusBar ()->showMessage (tr (" Sheet deleted: %1" ).arg (removed_name), 3000 );
416428}
417429
418- // Move current sheet one step left
430+ // move current sheet to the left
419431void MainWindow::on_sheet_move_left_button_clicked ()
420432{
421433 if (current_sheet_name_.isEmpty ()) {
@@ -424,7 +436,7 @@ void MainWindow::on_sheet_move_left_button_clicked()
424436
425437 const int idx = sheet_names_.indexOf (current_sheet_name_);
426438 if (idx <= 0 ) {
427- return ; // already first
439+ return ;
428440 }
429441
430442 sheet_names_.swapItemsAt (idx, idx - 1 );
@@ -434,7 +446,7 @@ void MainWindow::on_sheet_move_left_button_clicked()
434446 statusBar ()->showMessage (tr (" Sheet moved left" ), 2000 );
435447}
436448
437- // Move current sheet one step right
449+ // move current sheet to the right
438450void MainWindow::on_sheet_move_right_button_clicked ()
439451{
440452 if (current_sheet_name_.isEmpty ()) {
@@ -443,7 +455,7 @@ void MainWindow::on_sheet_move_right_button_clicked()
443455
444456 const int idx = sheet_names_.indexOf (current_sheet_name_);
445457 if (idx < 0 || idx >= sheet_names_.size () - 1 ) {
446- return ; // already last
458+ return ;
447459 }
448460
449461 sheet_names_.swapItemsAt (idx, idx + 1 );
@@ -453,7 +465,7 @@ void MainWindow::on_sheet_move_right_button_clicked()
453465 statusBar ()->showMessage (tr (" Sheet moved right" ), 2000 );
454466}
455467
456- // Update current sheet (table view, name edit, dataChanged connection)
468+ // set current sheet model / view
457469void MainWindow::set_current_sheet (const QString &sheet_name)
458470{
459471 if (!sheet_models_.contains (sheet_name)) {
@@ -479,7 +491,7 @@ void MainWindow::set_current_sheet(const QString &sheet_name)
479491 }
480492}
481493
482- // Apply QXlsx::Format to Qt item
494+ // apply QXlsx::Format to a Qt item
483495void MainWindow::apply_format_to_item (QStandardItemModel *model,
484496 int row,
485497 int col,
@@ -535,7 +547,7 @@ void MainWindow::apply_format_to_item(QStandardItemModel *model,
535547 }
536548}
537549
538- // Lookup format for a cell
550+ // look up cell format
539551Format MainWindow::format_for_cell (const QString &sheet_name,
540552 int row,
541553 int col) const
@@ -554,7 +566,7 @@ Format MainWindow::format_for_cell(const QString &sheet_name,
554566 return Format ();
555567}
556568
557- // Generate a unique sheet name like "Sheet1", "Sheet2", ...
569+ // generate a unique sheet name like "Sheet1", "Sheet2", ...
558570QString MainWindow::generate_unique_sheet_name () const
559571{
560572 QString base = QStringLiteral (" Sheet" );
@@ -568,7 +580,7 @@ QString MainWindow::generate_unique_sheet_name() const
568580 }
569581}
570582
571- // Rebuild the sheet combo box and keep the current sheet selected
583+ // rebuild sheet combobox and keep current sheet selection
572584void MainWindow::rebuild_sheet_combo (const QString ¤t_name)
573585{
574586 if (!sheet_combo_) {
@@ -587,8 +599,8 @@ void MainWindow::rebuild_sheet_combo(const QString ¤t_name)
587599 sheet_combo_->blockSignals (false );
588600}
589601
590- // Load all sheets from an Excel file
591- // All rows ( including row 1) are loaded as data, so row 1 is editable.
602+ // load all sheets from an Excel file
603+ // all rows including the first row are loaded as data, so row 1 is editable.
592604bool MainWindow::load_excel_file (const QString &file_path)
593605{
594606 Document xlsx (file_path);
@@ -646,7 +658,7 @@ bool MainWindow::load_excel_file(const QString &file_path)
646658
647659 for (int r = first_row; r <= last_row; ++r) {
648660 for (int c = first_col; c <= last_col; ++c) {
649- auto cell = sheet->cellAt (r, c); // shared_ptr<Cell>
661+ auto cell = sheet->cellAt (r, c);
650662 if (!cell) {
651663 continue ;
652664 }
@@ -695,7 +707,7 @@ bool MainWindow::load_excel_file(const QString &file_path)
695707 return true ;
696708}
697709
698- // Save all sheets in memory to an Excel file
710+ // save all sheets in memory into an Excel file
699711bool MainWindow::save_excel_file (const QString &file_path)
700712{
701713 if (sheet_names_.isEmpty ()) {
@@ -773,10 +785,98 @@ void MainWindow::on_action_about_triggered()
773785 " <li>Editable sheet data</li>"
774786 " <li>Sheet rename / add / delete / reorder</li>"
775787 " <li>Basic cell formatting</li>"
788+ " <li>Insert rows / columns</li>"
776789 " </ul>" ;
777790 text += " <br>Project: <a href=\" https://github.com/QtExcel/QXlsx\" >QXlsx GitHub</a><br>" ;
778791 text += " First Author: Jay Two<br>" ;
779792
780793 QMessageBox::about (this , tr (" About ExcelTableEditor" ), text);
781794}
782795
796+ // ----------------------------
797+ // row / column insertion logic
798+ // ----------------------------
799+
800+ // row insertion button: insert a new row above the selected row,
801+ // or append to the bottom if nothing is selected
802+ void MainWindow::on_add_row_button_clicked ()
803+ {
804+ if (!current_model_) {
805+ return ;
806+ }
807+
808+ int insert_row = current_model_->rowCount ();
809+
810+ if (table_view_ && table_view_->selectionModel ()) {
811+ const QModelIndexList indexes =
812+ table_view_->selectionModel ()->selectedIndexes ();
813+ if (!indexes.isEmpty ()) {
814+ insert_row = indexes.first ().row ();
815+ // find the topmost row among selected cells
816+ for (const QModelIndex &idx : indexes) {
817+ if (idx.row () < insert_row) {
818+ insert_row = idx.row ();
819+ }
820+ }
821+ }
822+ }
823+
824+ current_model_->insertRow (insert_row);
825+
826+ // update vertical header numbers (1,2,3,...)
827+ const int row_count = current_model_->rowCount ();
828+ for (int r = 0 ; r < row_count; ++r) {
829+ current_model_->setHeaderData (r, Qt::Vertical, QString::number (r + 1 ));
830+ }
831+
832+ // for simplicity, clear the format map after row insertion
833+ // (format indices would be shifted otherwise)
834+ if (!current_sheet_name_.isEmpty ()) {
835+ sheet_formats_[current_sheet_name_].clear ();
836+ }
837+
838+ is_modified_ = true ;
839+ statusBar ()->showMessage (tr (" Row inserted" ), 2000 );
840+ }
841+
842+ // column insertion button: insert a new column to the left of the selected column,
843+ // or append to the right if nothing is selected
844+ void MainWindow::on_add_column_button_clicked ()
845+ {
846+ if (!current_model_) {
847+ return ;
848+ }
849+
850+ int insert_col = current_model_->columnCount ();
851+
852+ if (table_view_ && table_view_->selectionModel ()) {
853+ const QModelIndexList indexes =
854+ table_view_->selectionModel ()->selectedIndexes ();
855+ if (!indexes.isEmpty ()) {
856+ insert_col = indexes.first ().column ();
857+ // find the leftmost column among selected cells
858+ for (const QModelIndex &idx : indexes) {
859+ if (idx.column () < insert_col) {
860+ insert_col = idx.column ();
861+ }
862+ }
863+ }
864+ }
865+
866+ current_model_->insertColumn (insert_col);
867+
868+ // update horizontal header numbers (1,2,3,...)
869+ const int col_count = current_model_->columnCount ();
870+ for (int c = 0 ; c < col_count; ++c) {
871+ current_model_->setHeaderData (c, Qt::Horizontal, QString::number (c + 1 ));
872+ }
873+
874+ // for simplicity, clear the format map after column insertion
875+ // (format indices would be shifted otherwise)
876+ if (!current_sheet_name_.isEmpty ()) {
877+ sheet_formats_[current_sheet_name_].clear ();
878+ }
879+
880+ is_modified_ = true ;
881+ statusBar ()->showMessage (tr (" Column inserted" ), 2000 );
882+ }
0 commit comments