void DocHistory::OnMouseLeftDown(wxMouseEvent& event) { const int y = event.GetY() + m_scrollPos; // Which node are we over? int node_id = -1; for (unsigned int i = 0; i < m_items.size(); ++i) { const int node_ypos = m_items[i].ypos; if (y >= node_ypos && y < (node_ypos + m_lineHeight)) { node_id = i; break; } } if (node_id != -1) { // We do not have to set the document now. We will recieve // a WIN_CHANGEDOC notifer if the documents actually gets // set on a page. // Do not return a reference. The events might modify // m_items underneath it. const doc_id hot_doc = m_items[node_id].doc; if (hot_doc.IsDraft()) { doc_id draft_head; cxLOCK_READ(m_catalyst) draft_head = catalyst.GetDraftHead(hot_doc.document_id); cxENDLOCK m_dispatcher.Notify(wxT("WIN_SETDOCUMENT"), &draft_head, m_source_win_id); } else m_dispatcher.Notify(wxT("WIN_SETDOCUMENT"), &hot_doc, m_source_win_id); } }
void DocHistory::SetDocument(const doc_id& di) { //wxASSERT(m_catalyst.IsOk(di)); // Check if we are invalidating the view if (!di.IsOk()) { Clear(); return; } if (m_sourceDoc != di) { cxLOCKDOC_WRITE(m_doc) doc.SetDocument(di); // Get the document m_document_id = di.IsDraft() ? doc.GetParent().document_id : di.document_id; cxENDLOCK m_sourceDoc = di; // Check if we need to rebuild the tree ReBuildTree(); } Select(m_selectedNode); MakeItemVisible(m_selectedNode); }
void DocHistory::OnVersionTreeSel(VersionTreeEvent& event) { wxASSERT(event.GetItem() >= 0 && event.GetItem() < m_items.size()); // Do not return a reference. The events might modify // m_items underneath it. const doc_id hot_doc = m_items[event.GetItem()].doc; // We do not have to set the document now. We will recieve // a WIN_CHANGEDOC notifer if the documents actually gets // set on a page. if (hot_doc.IsDraft()) { doc_id draft_head; cxLOCK_READ(m_catalyst) draft_head = catalyst.GetDraftHead(hot_doc.document_id); cxENDLOCK m_dispatcher.Notify(wxT("WIN_SETDOCUMENT"), &draft_head, m_source_win_id); } else m_dispatcher.Notify(wxT("WIN_SETDOCUMENT"), &hot_doc, m_source_win_id); }
void DocHistory::AddChildren(int parent_pos, const doc_id& di, const doc_id& sel_doc, const Catalyst& catalyst) { wxASSERT(di.IsDocument()); const int childCount = catalyst.GetChildCount(di); for (int i = 0; i < childCount; ++i) { const doc_id child = catalyst.GetChildID(di, i); item new_item; new_item.doc = child; new_item.date = catalyst.GetDocDate(child); new_item.parent = parent_pos; // Find the insert pos size_t n; for (n = parent_pos+1; n < m_items.size(); ++n) { if (new_item.date < m_items[n].date) { m_items.insert(m_items.begin()+n, new_item); // The indexes under the insertion has moved, so // we also have to update any references to this range if (m_selectedNode >= (int)n) ++m_selectedNode; for (size_t n2 = n+1; n2 < m_items.size(); ++n2) { int& parent = m_items[n2].parent; if (parent >= (int)n) ++parent; } break; } } if (n == m_items.size()) { m_items.push_back(new_item); } // Check if this is the selected node if (child.IsDocument()) { if (child == sel_doc) m_selectedNode = n; AddChildren(n, child, sel_doc, catalyst); } else if (child.SameDoc(sel_doc)) m_selectedNode = n; } }
void DiffLineCell::CalcLayout(const doc_id& rev1, const doc_id& rev2) { wxASSERT(rev1.IsOk()); wxASSERT(rev2.IsOk()); wxASSERT(char_width > 0); Clear(); cxLOCKDOC_READ(m_doc) if (rev1 == rev2) { // root has itself as parent int length = doc.GetVersionLength(rev2); if (length > 0) { length = wxMin(length, (int)doc.GetCharPos(rev2, 0, (width/char_width)+1)); wxString text = doc.GetTextPart(rev2, 0, length); CalcSubCells(text, *wxBLACK, m_insertColour); } } else if (!doc.TextChanged(rev1, rev2)) { if (doc.PropertiesChanged(rev1, rev2)) CalcSubCells(_("Properties Changed"), *wxBLACK, bgcolor); } else { bool change = false; const std::vector<match> matchlist = doc.Diff(rev1, rev2); unsigned int pos1 = 0; unsigned int pos2 = 0; unsigned int i = 0; while (i < matchlist.size()) { if (line_width > width) { // No need to parse something that won't be drawn break; } // Calculate how many chars there are room for in // the visible part. Then we can avoid retrieving // long strings (which can be *very* long) int chars_left = ((width-line_width)/char_width)+1; match m = matchlist[i]; if (pos1 < m.iv1_start_pos) { // Deleted unsigned int last_endpos = doc.GetCharPos(rev1, pos1, chars_left); CalcSubCells(doc.GetTextPart(rev1, pos1, wxMin(m.iv1_start_pos, last_endpos)), *wxBLACK, m_deleteColour); // PASTEL RED change = true; } if (pos2 < m.iv2_start_pos) { // Inserted unsigned int last_endpos = doc.GetCharPos(rev2, pos2, chars_left); CalcSubCells(doc.GetTextPart(rev2, pos2, wxMin(m.iv2_start_pos, last_endpos)), *wxBLACK, m_insertColour); // PASTEL GREEN change = true; } if (m.iv2_end_pos > 0 && m.iv2_end_pos > m.iv2_start_pos) { if (change) { unsigned int last_endpos = doc.GetCharPos(rev2, m.iv2_start_pos, chars_left); CalcSubCells(doc.GetTextPart(rev2, m.iv2_start_pos, wxMin(m.iv2_end_pos, last_endpos)), m_hiddenColour, bgcolor); } else { // Get up to 5 chars before first change unsigned int startpos = doc.GetCharPos(rev2, m.iv2_end_pos, -5); wxString initialText = doc.GetTextPart(rev2, wxMax(m.iv2_start_pos, startpos), m.iv2_end_pos); CalcSubCells(initialText, m_hiddenColour, bgcolor); } } pos1 = m.iv1_end_pos; pos2 = m.iv2_end_pos; ++i; } } cxENDLOCK }
void DiffLineCell::CalcLayoutRange(const doc_id& rev1, const doc_id& rev2, const interval& range) { wxASSERT(rev1.IsOk()); wxASSERT(rev2.IsOk()); wxASSERT(char_width > 0); Clear(); cxLOCKDOC_READ(m_doc) if (rev1 == rev2) { // root has itself as parent // Get up to 5 chars before range if (range.start > 0) { const unsigned int startpos = doc.GetCharPos(rev2, range.start, -5); const wxString initialText = doc.GetTextPart(rev2, wxMax(0, startpos), range.start); CalcSubCells(initialText, m_hiddenColour, bgcolor); } // Get the range unsigned int chars_left = ((width - line_width) / char_width)+1; unsigned int end = wxMin(range.end, doc.GetCharPos(rev2, range.start, chars_left)); unsigned int length = end - range.start; if (length == 0) return; const wxString text = doc.GetTextPart(rev2, range.start, length); CalcSubCells(text, *wxBLACK, m_insertColour); // Get text after range chars_left = ((width - line_width) / char_width)+1; length = doc.GetCharPos(rev2, range.end, chars_left); if (length == 0) return; const wxString text2 = doc.GetTextPart(rev2, range.start, length); CalcSubCells(text2, m_hiddenColour, bgcolor); } else { bool change = false; const std::vector<match> matchlist = doc.Diff(rev1, rev2); unsigned int pos1 = 0; unsigned int pos2 = 0; // Advance to range start (ignoring sentinel at end) unsigned int i = 0; while (i+1 < matchlist.size() && matchlist[i].iv2_end_pos < range.start) { pos1 = matchlist[i].iv1_end_pos; pos2 = matchlist[i].iv2_end_pos; ++i; } while (i < matchlist.size()) { if (line_width > width) break; // No need to parse something that won't be drawn // Calculate how many chars there are room for in // the visible part. Then we can avoid retrieving // long strings (which can be *very* long) int chars_left = ((width-line_width)/char_width)+1; const match& m = matchlist[i]; if (pos1 < m.iv1_start_pos && pos2 >= range.start && pos2 <= range.end) { // Deleted (and in range) const unsigned int last_endpos = doc.GetCharPos(rev1, pos1, chars_left); CalcSubCells(doc.GetTextPart(rev1, pos1, wxMin(m.iv1_start_pos, last_endpos)), *wxBLACK, m_deleteColour); // PASTEL RED change = true; } if (pos2 < m.iv2_start_pos && range.start < m.iv2_start_pos) { // Inserted // Get text before range if (pos2 < range.start) { const unsigned int ins_start = wxMax(pos2, doc.GetCharPos(rev2, range.start, -5)); CalcSubCells(doc.GetTextPart(rev2, ins_start, range.start), m_hiddenColour, bgcolor); } // Get text in range (only if overlap) if (pos2 < range.end && m.iv2_start_pos > range.start) { const unsigned int start_pos = wxMax(pos2, range.start); const unsigned int last_endpos = wxMin(wxMin(range.end, m.iv2_start_pos), doc.GetCharPos(rev2, start_pos, chars_left)); CalcSubCells(doc.GetTextPart(rev2, start_pos, last_endpos), *wxBLACK, m_insertColour); // PASTEL GREEN } // Get text after range if (m.iv2_start_pos > range.end) { const unsigned int rest_start = wxMax(pos2, range.end); const unsigned int rest_end = wxMin(m.iv2_start_pos, doc.GetCharPos(rev2, rest_start, chars_left)); CalcSubCells(doc.GetTextPart(rev2, rest_start, rest_end), m_hiddenColour, bgcolor); } change = true; } if (m.iv2_end_pos > 0 && m.iv2_end_pos > m.iv2_start_pos) { if (change) { const unsigned int last_endpos = doc.GetCharPos(rev2, m.iv2_start_pos, chars_left); CalcSubCells(doc.GetTextPart(rev2, m.iv2_start_pos, wxMin(m.iv2_end_pos, last_endpos)), m_hiddenColour, bgcolor); } else { // Get up to 5 chars before first change const unsigned int startpos = doc.GetCharPos(rev2, m.iv2_end_pos, -5); const wxString initialText = doc.GetTextPart(rev2, wxMax(m.iv2_start_pos, startpos), m.iv2_end_pos); CalcSubCells(initialText, m_hiddenColour, bgcolor); } } pos1 = m.iv1_end_pos; pos2 = m.iv2_end_pos; ++i; } } cxENDLOCK }
void RevTooltip::SetDocument(const doc_id& di, wxPoint pos) { Hide(); cxLOCK_READ(m_catalyst) wxASSERT(catalyst.IsOk(di)); m_docId = di; // Set the user info const unsigned int userId = catalyst.GetDocAuthor(m_docId); m_userPic->SetBitmap(catalyst.GetUserPic(userId)); m_userName->SetLabel(catalyst.GetUserName(userId)); if (userId == 0) m_userColor->Hide(); else { m_userColor->SetBackgroundColour(catalyst.GetUserColor(userId)); m_userColor->Show(); } // Set the Label wxString label = catalyst.GetLabel(m_docId); if (!label.empty()) label += wxT(":"); m_labelCtrl->SetLabel(label); // Set the Date const wxDateTime date = catalyst.GetDocDate(m_docId); const wxString age = catalyst.GetDocAge(m_docId); const wxString longdate = date.Format(wxT("%A, %B %d, %Y - %X ")) + wxString::Format(wxT("(%s)"),age.c_str()); m_dateCtrl->SetLabel(longdate); // Set the Comment m_descCtrl->SetLabel(catalyst.GetDescription(m_docId)); // Show paths to mirrors (if available) if (catalyst.IsMirrored(di)) { m_mainSizer->Show(m_mirrorSizer, true, true); wxArrayString paths; if (di.IsDraft()) catalyst.GetMirrorPathsForDraft(di, paths); // gets mirrors for all draft revisions else catalyst.GetMirrorPaths(di, paths); if (!paths.IsEmpty()) { wxString tip = paths[0]; for (size_t i = 1; i < paths.GetCount(); ++i) { tip += wxT("\n"); tip += paths[i]; } m_mirrorlistCtrl->SetLabel(tip); } else wxASSERT(false); } else m_mainSizer->Show(m_mirrorSizer, false, true); cxENDLOCK m_mainSizer->Layout(); m_mainSizer->SetSizeHints(m_mainPanel); m_mainSizer->SetSizeHints(this); // Get the size of the screen const int screen_x = wxSystemSettings::GetMetric(wxSYS_SCREEN_X); const int screen_y = wxSystemSettings::GetMetric(wxSYS_SCREEN_Y); // Get the size of the mouse cursor // BUG WORKAROUND: GetMetric gives how large it _can_ be (32*32) not // how large the actual visible image is. const int cursor_x = 16; // wxSystemSettings::GetMetric(wxSYS_CURSOR_X); const int cursor_y = 17; // wxSystemSettings::GetMetric(wxSYS_CURSOR_Y); const wxSize size = GetSize(); // Calculate the correct placement // (pos is assumed to be upper left corner of cursor) if (pos.x + cursor_x + size.x > screen_x) pos.x -= size.x + 3; else pos.x += cursor_x; if (pos.y + cursor_y + size.y > screen_y) pos.y -= size.y + 3; else pos.y += cursor_y; Move(pos); Show(); }