]> git.lyx.org Git - lyx.git/blobdiff - src/insets/insettabular.C
Fixes for tabular-clipboard-paste and tabular-scroll.
[lyx.git] / src / insets / insettabular.C
index 8e052f9eec167d9a49e90105d401c958921de3b0..33e15752363f3269120219d846890f6e964da969 100644 (file)
@@ -35,6 +35,7 @@
 #include "frontends/Dialogs.h"
 #include "debug.h"
 #include "lyxfunc.h"
+#include "WorkArea.h"
 
 const int ADD_TO_HEIGHT = 2;
 const int ADD_TO_TABULAR_WIDTH = 2;
@@ -50,6 +51,7 @@ using std::ifstream;
 using std::max;
 using std::endl;
 using std::swap;
+using std::max;
 
     
 struct tabular_features {
@@ -225,7 +227,6 @@ void InsetTabular::draw(BufferView * bv, LyXFont const & font, int baseline,
     Painter & pain = bv->painter();
     int i, j;
     int nx;
-    float cx;
 
     UpdatableInset::draw(bv, font, baseline, x, cleared);
     if (!cleared && ((need_update == INIT) || (need_update == FULL) ||
@@ -253,6 +254,7 @@ void InsetTabular::draw(BufferView * bv, LyXFont const & font, int baseline,
     x += ADD_TO_TABULAR_WIDTH;
     if (cleared) {
        int cell = 0;
+       float cx;
        for (i = 0; i < tabular->rows(); ++i) {
            nx = int(x);
            dodraw = ((baseline + tabular->GetDescentOfRow(i)) > 0) &&
@@ -319,10 +321,10 @@ void InsetTabular::draw(BufferView * bv, LyXFont const & font, int baseline,
            lyxerr[Debug::INSETS] << "ERROR this shouldn't happen\n";
            return;
        }
+//     LyXText::text_status st = bv->text->status;
 #if 0
-       LyXText::text_status st = bv->text->status;
        do {
-           cx = nx + tabular->GetBeginningOfTextInCell(cell);
+           float cx = nx + tabular->GetBeginningOfTextInCell(cell);
            bv->text->status = st;
            if (need_update == CELL) {
                // clear before the inset
@@ -346,7 +348,13 @@ void InsetTabular::draw(BufferView * bv, LyXFont const & font, int baseline,
            tabular->GetCellInset(cell)->draw(bv,font,baseline, cx, false);
        } while(bv->text->status == LyXText::CHANGED_IN_DRAW);
 #else
-       cx = nx + tabular->GetBeginningOfTextInCell(cell);
+       float dx;
+       float cx;
+       cx = dx = nx + tabular->GetBeginningOfTextInCell(cell);
+       tabular->GetCellInset(cell)->draw(bv,font,baseline, dx, false);
+       if (bv->text->status == LyXText::CHANGED_IN_DRAW)
+           return;
+       // clear only if we didn't have a change
        if (need_update == CELL) {
            // clear before the inset
            pain.fillRectangle(
@@ -366,9 +374,6 @@ void InsetTabular::draw(BufferView * bv, LyXFont const & font, int baseline,
                tabular->GetAscentOfRow(i) +
                tabular->GetDescentOfRow(i) - 1);
        }
-       tabular->GetCellInset(cell)->draw(bv,font,baseline, cx, false);
-       if (bv->text->status == LyXText::CHANGED_IN_DRAW)
-           return;
 #endif
     }
     x -= ADD_TO_TABULAR_WIDTH;
@@ -494,7 +499,7 @@ void InsetTabular::Edit(BufferView * bv, int x, int y, unsigned int button)
     sel_pos_start = sel_pos_end = cursor.pos();
     sel_cell_start = sel_cell_end = actcell;
     bv->text->FinishUndo();
-    if (InsetHit(bv, x, y)) {
+    if (InsetHit(bv, x, y) && (button != 3)) {
        ActivateCellInset(bv, x, y, button);
     }
 //    UpdateLocal(bv, NONE, false);
@@ -529,6 +534,8 @@ void InsetTabular::UpdateLocal(BufferView * bv, UpdateCodes what,
 {
     if (need_update < what) // only set this if it has greater update
        need_update = what;
+    if ((what == INIT) && hasSelection())
+       clearSelection();
     // Dirty Cast! (Lgb)
     if (need_update != NONE) {
        bv->updateInset(const_cast<InsetTabular *>(this), mark_dirty);
@@ -645,10 +652,14 @@ bool InsetTabular::InsertInset(BufferView * bv, Inset * inset)
 
 void InsetTabular::InsetButtonPress(BufferView * bv, int x, int y, int button)
 {
-    if (hasSelection() && (button != 3)) {
+    if (hasSelection() && (button == 3))
+       return;
+
+    if (hasSelection()) {
        clearSelection();
        UpdateLocal(bv, SELECTION, false);
     }
+
     no_selection = false;
 
     int const ocell = actcell;
@@ -660,6 +671,14 @@ void InsetTabular::InsetButtonPress(BufferView * bv, int x, int y, int button)
        UpdateLocal(bv, NONE, false);
     sel_pos_start = sel_pos_end = cursor.pos();
     sel_cell_start = sel_cell_end = actcell;
+    if (button == 3) {
+       if ((ocell != actcell) && the_locking_inset) {
+           the_locking_inset->InsetUnlock(bv);
+           the_locking_inset = 0;
+       }
+       ShowInsetCursor(bv);
+       return;
+    }
 
     bool const inset_hit = InsetHit(bv, x, y);
 
@@ -673,6 +692,10 @@ void InsetTabular::InsetButtonPress(BufferView * bv, int x, int y, int button)
        the_locking_inset->InsetUnlock(bv);
     }
     the_locking_inset = 0;
+    if (button == 2) {
+       LocalDispatch(bv, LFUN_PASTESELECTION, "paragraph");
+       return;
+    }
     if (inset_hit && bv->theLockingInset()) {
        if (ActivateCellInset(bv, x, y, button))
            the_locking_inset->InsetButtonPress(bv, x - inset_x,
@@ -767,15 +790,25 @@ UpdatableInset::RESULT InsetTabular::LocalDispatch(BufferView * bv, int action,
            the_locking_inset->ToggleInsetCursor(bv);
             return result;
         } else if (result == FINISHED) {
+           result = DISPATCHED;
            if ((action == LFUN_RIGHT) || (action == -1)) {
                cursor.pos(inset_pos + 1);
                resetPos(bv);
+           } else if (action == LFUN_DOWN) {
+               if (moveDown(bv) == FINISHED) {
+                   bv->unlockInset(this);
+                   result = FINISHED;
+               }
+           } else if (action == LFUN_UP) {
+               if (moveUp(bv) == FINISHED) {
+                   bv->unlockInset(this);
+                   result = FINISHED;
+               }
            }
            sel_pos_start = sel_pos_end = cursor.pos();
            sel_cell_start = sel_cell_end = actcell;
            the_locking_inset=0;
            ShowInsetCursor(bv);
-           result = DISPATCHED;
            return result;
        }
     }
@@ -930,21 +963,89 @@ UpdatableInset::RESULT InsetTabular::LocalDispatch(BufferView * bv, int action,
        bv->text->FinishUndo();
        copySelection(bv);
        break;
-    case LFUN_PASTE:
-       if (!hasPasteBuffer())
+    case LFUN_PASTESELECTION:
+    {
+       string clip(bv->workarea()->getClipboard());
+       
+       if (clip.empty())
            break;
-       bv->text->SetUndo(bv->buffer(), Undo::INSERT,
+       if (clip.find('\t') != string::npos) {
+           int cols = 1;
+           int rows = 1;
+           int maxCols = 1;
+           unsigned int len = clip.length();
+           string::size_type p = 0;
+
+           while((p < len) &&
+                 ((p = clip.find_first_of("\t\n", p)) != string::npos))
+           {
+               switch(clip[p]) {
+               case '\t':
+                   ++cols;
+                   break;
+               case '\n':
+                   if ((p+1) < len)
+                       ++rows;
+                   maxCols = max(cols, maxCols);
+                   cols = 1;
+                   break;
+               }
+               ++p;
+           }
+           maxCols = max(cols, maxCols);
+           delete paste_tabular;
+           paste_tabular = new LyXTabular(this, rows, maxCols);
+           string::size_type op = 0;
+           int cell = 0;
+           int cells = paste_tabular->GetNumberOfCells();
+           p = cols = 0;
+           while((cell < cells) && (p < len) &&
+                 (p = clip.find_first_of("\t\n", p)) != string::npos)
+           {
+               if (p >= len)
+                   break;
+               switch(clip[p]) {
+               case '\t':
+                   paste_tabular->GetCellInset(cell)->SetText(clip.substr(op, p-op));
+                   ++cols;
+                   ++cell;
+                   break;
+               case '\n':
+                   paste_tabular->GetCellInset(cell)->SetText(clip.substr(op, p-op));
+                   while(cols++ < maxCols)
+                       ++cell;
+                   cols = 0;
+                   break;
+               }
+               ++p;
+               op = p;
+           }
+           // check for the last cell if there is no trailing '\n'
+           if ((cell < cells) && (op < len))
+               paste_tabular->GetCellInset(cell)->SetText(clip.substr(op, len-op));
+       } else {
+           // so that the clipboard is used and it goes on to default
+           // and executes LFUN_PASTESELECTION in insettext!
+           delete paste_tabular;
+           paste_tabular = 0;
+       }
+    }
+    case LFUN_PASTE:
+       if (hasPasteBuffer()) {
+           bv->text->SetUndo(bv->buffer(), Undo::INSERT,
 #ifndef NEW_INSETS
-         bv->text->cursor.par()->ParFromPos(bv->text->cursor.pos())->previous,
-         bv->text->cursor.par()->ParFromPos(bv->text->cursor.pos())->next
+             bv->text->cursor.par()->ParFromPos(bv->text->cursor.pos())->previous,
+             bv->text->cursor.par()->ParFromPos(bv->text->cursor.pos())->next
 #else
-         bv->text->cursor.par()->previous,
-         bv->text->cursor.par()->next
+             bv->text->cursor.par()->previous,
+             bv->text->cursor.par()->next
 #endif
                );
-       pasteSelection(bv);
-       UpdateLocal(bv, INIT, true);
-       break;
+           pasteSelection(bv);
+           UpdateLocal(bv, INIT, true);
+           break;
+       }
+    // ATTENTION: the function above has to be PASTE and PASTESELECTION!!!
     default:
        // we try to activate the actual inset and put this event down to
        // the insets dispatch function.
@@ -1013,7 +1114,8 @@ bool InsetTabular::calculate_dimensions_of_cells(BufferView * bv,
                                                 bool reinit) const
 {
     int cell = -1;
-    int maxAsc, maxDesc;
+    int maxAsc = 0;
+    int maxDesc = 0;
     InsetText * inset;
     bool changed = false;
     
@@ -1021,15 +1123,20 @@ bool InsetTabular::calculate_dimensions_of_cells(BufferView * bv,
     // change so I'll try this to have a boost, but who knows ;)
     if ((need_update != INIT) &&
        (the_locking_inset == tabular->GetCellInset(actcell))) {
-       maxAsc = the_locking_inset->ascent(bv, font);
-       maxDesc = the_locking_inset->descent(bv, font);
+       for(int i = 0; i < tabular->columns(); ++i) {
+           maxAsc = max(tabular->GetCellInset(actrow, i)->ascent(bv, font),
+                        maxAsc);
+           maxDesc = max(tabular->GetCellInset(actrow, i)->descent(bv, font),
+                         maxDesc);
+       }
        changed = tabular->SetWidthOfCell(actcell, the_locking_inset->width(bv, font));
        changed = tabular->SetAscentOfRow(actrow, maxAsc + ADD_TO_HEIGHT) || changed;
        changed = tabular->SetDescentOfRow(actrow, maxDesc + ADD_TO_HEIGHT) || changed;
        return changed;
     }
     for (int i = 0; i < tabular->rows(); ++i) {
-       maxAsc = maxDesc = 0;
+       maxAsc = 0;
+       maxDesc = 0;
        for (int j= 0; j < tabular->columns(); ++j) {
            if (tabular->IsPartOfMultiColumn(i,j))
                continue;
@@ -1124,8 +1231,8 @@ void InsetTabular::setPos(BufferView * bv, int x, int y) const
     // now search the right column
     int lx = tabular->GetWidthOfColumn(actcell) -
        tabular->GetAdditionalWidth(actcell);
-#warning Jürgen, can you rewrite this to _not_ use the sequencing operator. (Lgb)
 #if 0
+#warning Jürgen, can you rewrite this to _not_ use the sequencing operator. (Lgb)
     for (; !tabular->IsLastCellInRow(actcell) && (lx < x);
        ++actcell,lx += tabular->GetWidthOfColumn(actcell) +
            tabular->GetAdditionalWidth(actcell - 1));
@@ -1182,6 +1289,7 @@ void InsetTabular::resetPos(BufferView * bv) const
     }
     static int const offset = ADD_TO_TABULAR_WIDTH + 2;
     int new_x = getCellXPos(actcell);
+    int old_x = cursor.x();
     new_x += offset;
     cursor.x(new_x);
 //    cursor.x(getCellXPos(actcell) + offset);
@@ -1198,6 +1306,9 @@ void InsetTabular::resetPos(BufferView * bv) const
        LyXFont font(LyXFont::ALL_SANE);
        cursor.x(cursor.x() + tabular->GetCellInset(actcell)->width(bv,font) +
                tabular->GetBeginningOfTextInCell(actcell));
+    } else if (scroll() && (top_x > 20) &&
+              ((top_x+tabular->GetWidthOfTabular()) > (bv->workWidth()-20))) {
+       scroll(bv, old_x - cursor.x());
     }
     if ((!the_locking_inset ||
         !the_locking_inset->GetFirstLockingInsetOfType(TABULAR_CODE)) &&
@@ -1724,7 +1835,7 @@ void InsetTabular::resizeLyXText(BufferView *) const
 }
 
 
-LyXText * InsetTabular::getLyXText(BufferView * bv) const
+LyXText * InsetTabular::getLyXText(BufferView const * bv) const
 {
     if (the_locking_inset)
        return the_locking_inset->getLyXText(bv);
@@ -2028,18 +2139,32 @@ bool InsetTabular::pasteSelection(BufferView * bv)
 {
     if (!paste_tabular)
        return false;
-    for (int j=0, i=actcell; j<paste_tabular->GetNumberOfCells(); ++j,++i) {
-       while (paste_tabular->row_of_cell(j) > tabular->row_of_cell(i)-actrow)
-           ++i;
-       if (tabular->GetNumberOfCells() <= i)
-           break;
-       while (paste_tabular->row_of_cell(j) < tabular->row_of_cell(i)-actrow)
-           ++j;
-       if (paste_tabular->GetNumberOfCells() <= j)
-           break;
-       *(tabular->GetCellInset(i)) = *(paste_tabular->GetCellInset(j));
-       tabular->GetCellInset(i)->setOwner(this);
-       tabular->GetCellInset(i)->deleteLyXText(bv);
+
+    for (int r1 = 0, r2 = actrow;
+        (r1 < paste_tabular->rows()) && (r2 < tabular->rows());
+        ++r1, ++r2)
+    {
+       for(int c1 = 0, c2 = actcol;
+           (c1 < paste_tabular->columns()) && (c2 < tabular->columns());
+           ++c1, ++c2)
+       {
+           if (paste_tabular->IsPartOfMultiColumn(r1,c1) &&
+               tabular->IsPartOfMultiColumn(r2,c2))
+               continue;
+           if (paste_tabular->IsPartOfMultiColumn(r1,c1)) {
+               --c2;
+               continue;
+           }
+           if (tabular->IsPartOfMultiColumn(r2,c2)) {
+               --c1;
+               continue;
+           }
+           int n1 = paste_tabular->GetCellNumber(r1, c1);
+           int n2 = tabular->GetCellNumber(r2, c2);
+           *(tabular->GetCellInset(n2)) = *(paste_tabular->GetCellInset(n1));
+           tabular->GetCellInset(n2)->setOwner(this);
+           tabular->GetCellInset(n2)->deleteLyXText(bv);
+       }
     }
     return true;
 }