Index: src/test/java/com/xpn/xwiki/doc/XWikiDocumentTest.java =================================================================== --- src/test/java/com/xpn/xwiki/doc/XWikiDocumentTest.java (revision 4044) +++ src/test/java/com/xpn/xwiki/doc/XWikiDocumentTest.java (working copy) @@ -79,4 +79,24 @@ assertEquals("Title", this.document.getDisplayTitle(this.context)); } + + public void testMinorMajorVersions() { + // there is no version in doc yet, so 1.1 + assertEquals("1.1", this.document.getVersion()); + + this.document.setMinorEdit(false); + this.document.incrementVersion(); + // no version => incrementVersion sets 1.1 + assertEquals("1.1", this.document.getVersion()); + + this.document.setMinorEdit(false); + this.document.incrementVersion(); + // increment major version + assertEquals("2.1", this.document.getVersion()); + + this.document.setMinorEdit(true); + this.document.incrementVersion(); + // increment minor version + assertEquals("2.2", this.document.getVersion()); + } } Index: src/test/java/com/xpn/xwiki/doc/XWikiDocumentArchiveTest.java =================================================================== --- src/test/java/com/xpn/xwiki/doc/XWikiDocumentArchiveTest.java (revision 4044) +++ src/test/java/com/xpn/xwiki/doc/XWikiDocumentArchiveTest.java (working copy) @@ -19,10 +19,19 @@ */ package com.xpn.xwiki.doc; +import java.util.Arrays; +import java.util.Date; + import junit.framework.TestCase; +import org.apache.tools.ant.filters.StringInputStream; +import org.suigeneris.jrcs.rcs.Archive; + +import com.xpn.xwiki.XWikiContext; +import com.xpn.xwiki.XWikiException; + /** - * Unit tests for {@link com.xpn.xwiki.doc.XWikiDocumentArchive}. + * Unit tests for {@link XWikiDocumentArchive}. * * @version $Id: $ */ @@ -37,31 +46,6 @@ */ public void testUpdateArchiveWhenSpaceInUsername() throws Exception { - String originalText = "\"\\n\\n" - + "\\nKnowledgeBase\\nWebHome\\n" - + "\\nen\\n0\\n" - + "Main.Notes\\nXWiki.Admin\\nXWiki.Admin" - + "\\n\\nXWiki.Admin\\n" - + "1165874272000\\n1172011434000\\n" - + "1172011434000\\n1.8\\n" - + "\\n\\n\\n" - + "\\n\\n\\nXWiki.TagClass" - + "\\n\\n\\n" - + "\\n\\n" - + "\\n\\n" - + "\\n\\ntags\\nTags\\n" - + "0\\n1\\n" - + "input\\n1\\n30\\n" - + " \\n ,|\\n\\n" - + "1\\ncom.xpn.xwiki.objects.classes.StaticListClass" - + "\\n\\n\\nKnowledgeBase.WebHome\\n" - + "0\\nXWiki.TagClass\\n\\n\\n" - + "\\n\\n1 Wiki Knowledge Base\\r\\n\\r\\nThis is the " - + "Wiki Knowledge Base, where you can start writing about your favorite subjects.\\r\\n" - + "\\r\\nTo create new pages, click edit button and write links using brackets around " - + "words.\\r\\n\\r\\n* [Example Link 1]\\r\\n* [Example Link 2]\\n" - + "\\n\""; - String originalArchive = "head\t1.1;\n" + "access;\n" + "symbols;\n" + @@ -153,12 +137,70 @@ // Set a username with a space System.setProperty("user.name", "Vincent Massol"); + + XWikiContext context = new XWikiContext(); + XWikiDocument doc = new XWikiDocument("Main", "WebHome"); + archive.updateArchive("XWiki.XWikiGuest", new Date(), "some comment", false, doc, context); - archive.updateArchive("Main.WebHome", originalText); - // Try to construct again the archive from the last modification. This will happen when // XWiki loads a document from the database for example. We verify here that a username // with a space works. - new XWikiDocumentArchive(123456789L).setArchive(archive.getArchive()); + new XWikiDocumentArchive(123456789L).setArchive(archive.getArchive(context)); } + + public void testUpdateLoad() throws XWikiException { + XWikiDocument doc = new XWikiDocument("Test", "Test"); + doc.setContent("content 1.1"); + + XWikiContext context = new XWikiContext(); + + XWikiDocumentArchive archive = new XWikiDocumentArchive(doc.getId()); + assertEquals(0, archive.getNodes().size()); + + String author = "some author"; + archive.updateArchive(author, new Date(), "initial, 1.1", false, doc, context); + String archive11 = archive.getArchive(context); + assertEquals(1, archive.getNodes().size()); + assertEquals(1, archive.getUpdeteNodeInfos().size()); + assertEquals(1, archive.getUpdeteNodeContents().size()); + + XWikiDocumentArchive archive2 = new XWikiDocumentArchive(doc.getId()); + archive2.setArchive(archive11); + assertEquals(archive11, archive2.getArchive(context)); + assertEquals(1, archive2.getNodes().size()); + assertEquals(1, archive2.getUpdeteNodeInfos().size()); + assertEquals(1, archive2.getUpdeteNodeContents().size()); + + doc.setContent("content\n1.2"); + archive.updateArchive(author, new Date(), "1.2", true, doc, context); + String archive12 = archive.getArchive(context); + assertEquals(2, archive.getNodes().size()); + assertEquals(2, archive.getUpdeteNodeInfos().size()); + assertEquals(2, archive.getUpdeteNodeContents().size()); + + XWikiDocumentArchive archive3 = new XWikiDocumentArchive(doc.getId()); + archive3.setArchive(archive12); + assertEquals(2, archive3.getNodes().size()); + assertEquals(2, archive3.getUpdeteNodeInfos().size()); + assertEquals(2, archive3.getUpdeteNodeContents().size()); + + doc.setContent("major change\ncontent\n2.1"); + archive.updateArchive(author, new Date(), "2.1", false, doc, context); + assertEquals(3, archive.getNodes().size()); + assertEquals(3, archive.getUpdeteNodeInfos().size()); + assertEquals(3, archive.getUpdeteNodeContents().size()); + } + + public void testJrcsQuote() throws Exception { + // test for http://www.suigeneris.org/issues/browse/JRCS-23 + Object[] text = {"qwe @ qwe", "qwe @@ qwe"}; + String log = "some bad @ log"; + Archive arch = new Archive(text, log); + String sarch = arch.toString(); + + Archive arch2 = new Archive("", new StringInputStream(sarch)); + assertEquals( sarch, arch2.toString() ); + assertTrue( Arrays.equals( text, arch2.getRevision() ) ); + assertEquals( log, arch2.getLog("1.1") ); + } } Index: src/main/java/com/xpn/xwiki/store/XWikiHibernateBaseStore.java =================================================================== --- src/main/java/com/xpn/xwiki/store/XWikiHibernateBaseStore.java (revision 4044) +++ src/main/java/com/xpn/xwiki/store/XWikiHibernateBaseStore.java (working copy) @@ -32,7 +32,6 @@ import java.util.Map; import java.util.Iterator; import java.lang.reflect.Proxy; -import java.lang.reflect.InvocationHandler; public class XWikiHibernateBaseStore { private static final Log log = LogFactory.getLog(XWikiHibernateBaseStore.class); @@ -787,4 +786,51 @@ ""; return custommapping; } + + /** spring-jcr like Callback interface for working in hibernate */ + public interface HibernateCallBack { + Object doInHibernate(Session session) throws Exception; + } + + /** spring-jcr like execute method for operations in hibernate + * @throws XWikiException */ + public Object execute(XWikiContext context, boolean bTransaction, boolean doCommit, HibernateCallBack cb) throws XWikiException { + MonitorPlugin monitor = Util.getMonitorPlugin(context); + try { + // Start monitoring timer + if (monitor!=null) + monitor.startTimer("hibernate"); + + if (bTransaction) { + checkHibernate(context); + bTransaction = beginTransaction(context); + } + + return cb.doInHibernate(getSession(context)); + } catch (Exception e) { + if (e instanceof XWikiException) + throw (XWikiException)e; + throw new XWikiException( XWikiException.MODULE_XWIKI_STORE, XWikiException.ERROR_XWIKI_UNKNOWN, + "Exception while hibernate execute", e); + } finally { + try { + if (bTransaction) + endTransaction(context, doCommit); + if (monitor!=null) + monitor.endTimer("hibernate"); + } catch (Exception e) {} + } + } + + /** spring-jcr like execute method for read-only operations in hibernate + * @throws XWikiException */ + public Object executeRead(XWikiContext context, boolean bTransaction, HibernateCallBack cb) throws XWikiException { + return execute(context, bTransaction, false, cb); + } + + /** spring-jcr like execute method for write operations in hibernate + * @throws XWikiException */ + public Object executeWrite(XWikiContext context, boolean bTransaction, HibernateCallBack cb) throws XWikiException { + return execute(context, bTransaction, true, cb); + } } Index: src/main/java/com/xpn/xwiki/store/XWikiHibernateStore.java =================================================================== --- src/main/java/com/xpn/xwiki/store/XWikiHibernateStore.java (revision 4044) +++ src/main/java/com/xpn/xwiki/store/XWikiHibernateStore.java (working copy) @@ -26,6 +26,7 @@ import com.xpn.xwiki.doc.XWikiDocument; import com.xpn.xwiki.doc.XWikiLink; import com.xpn.xwiki.doc.XWikiLock; +import com.xpn.xwiki.doc.rcs.XWikiRCSNodeInfo; import com.xpn.xwiki.monitor.api.MonitorPlugin; import com.xpn.xwiki.objects.*; import com.xpn.xwiki.objects.classes.BaseClass; @@ -235,7 +236,7 @@ } doc.incrementVersion(); if (context.getWiki().hasVersioning(doc.getFullName(), context)) - context.getWiki().getVersioningStore().updateXWikiDocArchive(doc, doc.toXML(context), false, context); + context.getWiki().getVersioningStore().updateXWikiDocArchive(doc, false, context); doc.setContentDirty(false); doc.setMetaDataDirty(false); @@ -531,7 +532,11 @@ deleteXWikiObject(obj, context, false); } } - + // Delete history + session.createQuery("delete from "+XWikiRCSNodeInfo.class.getName()+" where id.docId=?") + .setLong(0, doc.getId()) + .executeUpdate(); + session.delete(doc); // We need to ensure that the deleted document becomes the original document Index: src/main/java/com/xpn/xwiki/store/XWikiVersioningStoreInterface.java =================================================================== --- src/main/java/com/xpn/xwiki/store/XWikiVersioningStoreInterface.java (revision 4044) +++ src/main/java/com/xpn/xwiki/store/XWikiVersioningStoreInterface.java (working copy) @@ -1,18 +1,25 @@ package com.xpn.xwiki.store; +import org.suigeneris.jrcs.rcs.Version; + import com.xpn.xwiki.XWikiContext; import com.xpn.xwiki.XWikiException; import com.xpn.xwiki.doc.XWikiDocument; import com.xpn.xwiki.doc.XWikiDocumentArchive; -import org.suigeneris.jrcs.rcs.Version; +import com.xpn.xwiki.doc.rcs.XWikiRCSNodeContent; +import com.xpn.xwiki.doc.rcs.XWikiRCSNodeId; +import com.xpn.xwiki.doc.rcs.XWikiRCSNodeInfo; public interface XWikiVersioningStoreInterface { public void loadXWikiDocArchive(XWikiDocumentArchive archivedoc, boolean bTransaction, XWikiContext context) throws XWikiException; public void saveXWikiDocArchive(XWikiDocumentArchive archivedoc, boolean bTransaction, XWikiContext context) throws XWikiException; - public void updateXWikiDocArchive(XWikiDocument doc, String text, boolean bTransaction, XWikiContext context) throws XWikiException; + public void updateXWikiDocArchive(XWikiDocument doc, boolean bTransaction, XWikiContext context) throws XWikiException; public Version[] getXWikiDocVersions(XWikiDocument doc, XWikiContext context) throws XWikiException; - // public Archive getXWikiDocRCSArchive(XWikiDocument doc, XWikiContext context) throws XWikiException; public XWikiDocument loadXWikiDoc(XWikiDocument doc, String version, XWikiContext context) throws XWikiException; public void resetRCSArchive(XWikiDocument doc, boolean bTransaction, XWikiContext context) throws XWikiException; public XWikiDocumentArchive getXWikiDocumentArchive(XWikiDocument doc, XWikiContext context) throws XWikiException; + /** + * Load {@link XWikiRCSNodeContent} by demand. Used in {@link XWikiRCSNodeInfo#getContent(XWikiContext)} + */ + public XWikiRCSNodeContent loadRCSNodeContent(XWikiContext context, XWikiRCSNodeId id, boolean bTransaction) throws XWikiException; } Index: src/main/java/com/xpn/xwiki/store/XWikiHibernateVersioningStore.java =================================================================== --- src/main/java/com/xpn/xwiki/store/XWikiHibernateVersioningStore.java (revision 4044) +++ src/main/java/com/xpn/xwiki/store/XWikiHibernateVersioningStore.java (working copy) @@ -1,39 +1,41 @@ package com.xpn.xwiki.store; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.hibernate.Session; +import org.hibernate.criterion.Restrictions; +import org.suigeneris.jrcs.rcs.Version; +import org.suigeneris.jrcs.util.ToString; + import com.xpn.xwiki.XWiki; import com.xpn.xwiki.XWikiContext; import com.xpn.xwiki.XWikiException; import com.xpn.xwiki.doc.XWikiDocument; import com.xpn.xwiki.doc.XWikiDocumentArchive; -import com.xpn.xwiki.monitor.api.MonitorPlugin; -import com.xpn.xwiki.util.Util; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.hibernate.ObjectNotFoundException; -import org.hibernate.Session; -import org.suigeneris.jrcs.rcs.Archive; -import org.suigeneris.jrcs.rcs.Node; -import org.suigeneris.jrcs.rcs.Version; +import com.xpn.xwiki.doc.rcs.XWikiDiff; +import com.xpn.xwiki.doc.rcs.XWikiRCSNodeContent; +import com.xpn.xwiki.doc.rcs.XWikiRCSNodeId; +import com.xpn.xwiki.doc.rcs.XWikiRCSNodeInfo; public class XWikiHibernateVersioningStore extends XWikiHibernateBaseStore implements XWikiVersioningStoreInterface { private static final Log log = LogFactory.getLog(XWikiHibernateVersioningStore.class); /** - * THis allows to initialize our storage engine. - * The hibernate config file path is taken from xwiki.cfg - * or directly in the WEB-INF directory. - * @param xwiki - * @param context + * {@inheritDoc} */ public XWikiHibernateVersioningStore(XWiki xwiki, XWikiContext context) { super(xwiki, context); } /** - * Initialize the storage engine with a specific path - * This is used for tests. - * @param hibpath + * {@inheritDoc} */ public XWikiHibernateVersioningStore(String hibpath) { super(hibpath); @@ -41,14 +43,15 @@ public Version[] getXWikiDocVersions(XWikiDocument doc, XWikiContext context) throws XWikiException { try { - Archive archive = getXWikiDocumentArchive(doc, context).getRCSArchive(); + XWikiDocumentArchive archive = getXWikiDocumentArchive(doc, context); if (archive==null) return new Version[0]; - - Node[] nodes = archive.changeLog(); - Version[] versions = new Version[nodes.length]; - for (int i=0;i 0) { + for (Iterator it = nodeInfos.iterator(); it.hasNext();) { + XWikiRCSNodeInfo nodeinfo = (XWikiRCSNodeInfo) it.next(); + XWikiJRCSNode node = new XWikiJRCSNode(nodeinfo.getId().getVersion(), null); + node.setAuthor(nodeinfo.getAuthor()); + node.setDate(nodeinfo.getDate()); + node.setLog(nodeinfo.getComment()); + node.setPatch(nodeinfo.isPatch()); + XWikiRCSNodeContent content = nodeinfo.getContent(context); + node.setText(content.getDelta()); + nodes.put(node.getVersion(), node); + } + XWikiJRCSNode last = null; + for (Iterator it = nodes.keySet().iterator(); it.hasNext();) { + Version ver = (Version) it.next(); + XWikiJRCSNode node = (XWikiJRCSNode) nodes.get(ver); + if (last != null) { + last.setRCSNext(node); + } + last = node; + if (head == null) { + head = node; + } + } + } + } + /** + * Used to deserialize {@link XWikiDocumentArchive}. + * @param archivetext - archive text in JRCS format + * @throws ParseException if syntax errors + */ + public XWikiRCSArchive(String archivetext) throws ParseException + { + super("", new StringInputStream(archivetext)); + } + /** + * Helper class for convert from {@link XWikiRCSNodeInfo} to JRCS {@link Node}. + */ + private static class XWikiJRCSNode extends TrunkNode + { + /** bug if author=="". */ + public static String sauthorIfEmpty = "_"; + /** mark that node contains not patch. */ + public static String sfullVersion = "full"; + /** + * @param vernum - version of node + * @param next - next node (with smaller version) in history + * @throws InvalidTrunkVersionNumberException if version is invalid + */ + public XWikiJRCSNode(Version vernum, TrunkNode next) + throws InvalidTrunkVersionNumberException + { + super(vernum, next); + } + /** @param node - create class from copying this node */ + public XWikiJRCSNode(Node other) + { + this(other.version, null); + this.date = other.getDate(); + this.author = other.getAuthor(); + this.state = other.getState(); + this.log = other.getLog(); + this.locker = other.getLocker(); + this.setText(other.getText()); + } + /** @param date - date of modification */ + public void setDate(Date date) { + this.date = date; + } + /** {@inheritDoc} */ + public void setAuthor(String user) + { + // + if (user == null || "".equals(user)) { + super.setAuthor(sauthorIfEmpty); + } else { + super.setAuthor(user); + } + } + /** @return is this node store patch or full version */ + public boolean isPatch() { + // we need something filed in Node. locker is free + return !sfullVersion.equals(getState()); + } + /** @param ispatch - true if node stores a patch, false - if full version */ + public void setPatch(boolean ispatch) { + setState(ispatch ? "patch" : sfullVersion); + } + } + + /** + * @return Collection of pairs [{@link XWikiRCSNodeInfo}, {@link XWikiRCSNodeContent}] + * @param docId - docId which will be wrote in {@link XWikiRCSNodeId#setDocId(long)} + */ + public Collection getNodes(long docId) { + Collection result = new ArrayList(nodes.values().size()); + for (Iterator it = nodes.values().iterator(); it.hasNext();) { + XWikiJRCSNode node = new XWikiJRCSNode( (Node) it.next() ); + XWikiRCSNodeInfo nodeinfo = new XWikiRCSNodeInfo(); + nodeinfo.setId(new XWikiRCSNodeId(docId, node.getVersion())); + nodeinfo.setAuthor(XWikiJRCSNode.sauthorIfEmpty.equals(node.getAuthor()) + ? "" : node.getAuthor()); + nodeinfo.setComment(node.getLog()); + nodeinfo.setDate(node.getDate()); + nodeinfo.setPatch(node.isPatch()); + XWikiRCSNodeContent content = new XWikiRCSNodeContent(nodeinfo.getId()); + content.setDelta(ToString.arrayToString(node.getText())); + nodeinfo.setContent(content); + result.add(nodeinfo); + result.add(content); + } + // ensure latest version is full + ((XWikiRCSNodeInfo) result.iterator().next()).setPatch(false); + return result; + } +} Property changes on: src/main/java/com/xpn/xwiki/doc/rcs/XWikiRCSArchive.java ___________________________________________________________________ Name: svn:eol-style + native Index: src/main/java/com/xpn/xwiki/doc/rcs/XWikiRCSNodeId.java =================================================================== --- src/main/java/com/xpn/xwiki/doc/rcs/XWikiRCSNodeId.java (revision 0) +++ src/main/java/com/xpn/xwiki/doc/rcs/XWikiRCSNodeId.java (revision 0) @@ -0,0 +1,175 @@ +/* + * Copyright 2007, XpertNet SARL, and individual contributors as indicated + * by the contributors.txt. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ +package com.xpn.xwiki.doc.rcs; + +import java.io.Serializable; + +import org.apache.commons.lang.builder.EqualsBuilder; +import org.apache.commons.lang.builder.HashCodeBuilder; +import org.apache.commons.lang.builder.ToStringBuilder; +import org.suigeneris.jrcs.rcs.Version; + +/** + * Composite ID component used in {@link XWikiRCSNodeInfo} & {@link XWikiRCSNodeContent}. + * Mutable. + * @version $Id: $ + */ +public class XWikiRCSNodeId implements Serializable, Cloneable +{ + // composite-key + /** + * = {@link XWikiDocument#getId()}. + * part of composite key + */ + private long docId; + /** + * version of document. + * part of composite key + */ + private Version version = new Version(1, 1); + + /** + * default constructor used in Hibernate to load this class. + */ + public XWikiRCSNodeId() { } + + /** + * @param docId = {@link XWikiDocument#getId()} + * @param version - version of document + */ + public XWikiRCSNodeId(long docId, Version version) + { + super(); + this.docId = docId; + this.version = version; + } + + /*/** + * Clone-constructor. + * @param node - clone from what node + * + public XWikiRCSNodeId(XWikiRCSNodeId node) + { + this(node.getDocId(), node.getVersion()); + }*/ + + /** + * @return {@link XWikiDocument#getId()} + */ + public long getDocId() + { + return docId; + } + + /** + * @param docId = {@link XWikiDocument#getId()} + */ + public void setDocId(long docId) + { + this.docId = docId; + } + + /** + * @return version of document + */ + public Version getVersion() + { + return version; + } + /** + * @return 1st number in version + * used in Hibernate to store this class + */ + protected int getVersion1() + { + return version.at(0); + } + /** + * @return 2nd number in version + * used in Hibernate to store this class + */ + protected int getVersion2() + { + return version.at(1); + } + /** + * @param ver - version of document + */ + public void setVersion(Version ver) + { + this.version = ver; + } + /** + * @param v1 = 1st number in version + * used in Hibernate to load this class + */ + protected void setVersion1(int v1) + { + this.version = new Version(v1, version.at(1)); + } + /** + * @param v2 = 2nd number in version + * used in Hibernate to load this class + */ + protected void setVersion2(int v2) + { + this.version = new Version(version.at(0), v2); + } + + /** + * {@inheritDoc} + */ + public int hashCode() + { + return HashCodeBuilder.reflectionHashCode(this); + } + + /** + * {@inheritDoc} + */ + public boolean equals(Object obj) + { + return EqualsBuilder.reflectionEquals(this, obj); + } + + /** + * {@inheritDoc} + * @throws CloneNotSupportedException + */ + public Object clone() + { + try { + // there are no mutable fields, so simple do super.clone() + return super.clone(); + } catch (CloneNotSupportedException e) { + // clone is supported. exception is nonsense. + throw new RuntimeException(e); + } + } + + /** + * {@inheritDoc} + */ + public String toString() + { + return ToStringBuilder.reflectionToString(this); + } +} Property changes on: src/main/java/com/xpn/xwiki/doc/rcs/XWikiRCSNodeId.java ___________________________________________________________________ Name: svn:eol-style + native Index: src/main/java/com/xpn/xwiki/doc/XWikiDocument.java =================================================================== --- src/main/java/com/xpn/xwiki/doc/XWikiDocument.java (revision 4044) +++ src/main/java/com/xpn/xwiki/doc/XWikiDocument.java (working copy) @@ -28,6 +28,7 @@ import com.xpn.xwiki.content.parsers.ReplacementResultCollection; import com.xpn.xwiki.content.parsers.RenamePageReplaceLinkHandler; import com.xpn.xwiki.content.Link; +import com.xpn.xwiki.doc.rcs.XWikiRCSNodeInfo; import com.xpn.xwiki.api.DocumentSection; import com.xpn.xwiki.notify.XWikiNotificationRule; import com.xpn.xwiki.objects.BaseCollection; @@ -156,6 +157,9 @@ // Comment on the latest modification private String comment; + + // Is latest modification is minor edit + private boolean isMinorEdit = false; // Used to make sure the MetaData String is regenerated private boolean isContentDirty = true; @@ -285,13 +289,17 @@ public void setVersion(String version) { - this.version = new Version(version); + if (version!=null && !"".equals(version)) { + this.version = new Version(version); + } } public Version getRCSVersion() { if (version == null) { - version = new Version("1.1"); + // if we assign this.version = new Version("1.1") before save (ex: $doc.getVersion() in a page), then version will be > 1.1 after the first save + // version 1.0 do not work for some reason inside JRCS + return new Version("1.1"); } return version; } @@ -669,7 +677,11 @@ if (version == null) { version = new Version("1.1"); } else { - version = version.next(); + if (isMinorEdit()) { + version = version.next(); + } else { + version = version.getBranchPoint().next().newBranch(1); + } } } @@ -851,6 +863,14 @@ { XWikiDocumentArchive xda = new XWikiDocumentArchive(getId()); xda.setArchive(sarch); + if (xda.getNodes().size()>0) { + setRCSVersion(xda.getLatestVersion()); + XWikiRCSNodeInfo nodeinfo = xda.getLatestNode(); + setComment(nodeinfo.getComment()); + setMinorEdit(nodeinfo.isMinorEdit()); + setAuthor(nodeinfo.getAuthor()); + setDate(nodeinfo.getDate()); + } setDocumentArchive(xda); } @@ -885,6 +905,11 @@ } } + public XWikiRCSNodeInfo getRevisionInfo(String version, XWikiContext context) throws XWikiException + { + return getDocumentArchive(context).getNode(new Version(version)); + } + public boolean isMostRecent() { return mostRecent; @@ -1548,7 +1573,10 @@ if (comment != null) { setComment(comment); } - + + // Read the minor edit checkbox from the form + setMinorEdit(eform.isMinorEdit()); + String tags = eform.getTags(); if (tags != null) { setTags(tags, context); @@ -1786,6 +1814,7 @@ setxWikiClass((BaseClass) document.getxWikiClass().clone()); setxWikiClassXML(document.getxWikiClassXML()); setComment(document.getComment()); + setMinorEdit(document.isMinorEdit()); clonexWikiObjects(document); copyAttachments(document); @@ -1835,6 +1864,7 @@ doc.setxWikiClass((BaseClass) getxWikiClass().clone()); doc.setxWikiClassXML(getxWikiClassXML()); doc.setComment(getComment()); + doc.setMinorEdit(isMinorEdit()); doc.clonexWikiObjects(this); doc.copyAttachments(this); doc.elements = elements; @@ -1960,6 +1990,10 @@ if (!getComment().equals(doc.getComment())) { return false; } + + if (isMinorEdit() == doc.isMinorEdit()) { + return false; + } if (!getxWikiClass().equals(doc.getxWikiClass())) { return false; @@ -2078,7 +2112,7 @@ Document doc = new DOMDocument(); Element docel = new DOMElement("xwikidoc"); doc.setRootElement(docel); - + Element el = new DOMElement("web"); el.addText(getSpace()); docel.add(el); @@ -2157,13 +2191,17 @@ el = new DOMElement("comment"); el.addText(getComment()); docel.add(el); - + + el = new DOMElement("minorEdit"); + el.addText(String.valueOf(isMinorEdit())); + docel.add(el); + List alist = getAttachmentList(); for (int ai = 0; ai < alist.size(); ai++) { XWikiAttachment attach = (XWikiAttachment) alist.get(ai); docel.add(attach.toXML(bWithAttachmentContent, bWithVersions, context)); } - + if (bWithObjects) { // Add Class BaseClass bclass = getxWikiClass(); @@ -2213,7 +2251,7 @@ if (bWithVersions) { el = new DOMElement("versions"); try { - el.addText(getDocumentArchive(context).getArchive()); + el.addText(getDocumentArchive(context).getArchive( context )); } catch (XWikiException e) { return null; } @@ -2222,7 +2260,7 @@ return doc; } - + protected String encodedXMLStringAsUTF8(String xmlString) { if (xmlString == null) { @@ -2341,6 +2379,9 @@ setValidationScript(getElement(docel, "validationScript")); setComment(getElement(docel, "comment")); + String minorEdit = getElement(docel, "minorEdit"); + setMinorEdit(Boolean.valueOf(minorEdit).booleanValue()); + String strans = getElement(docel, "translation"); if ((strans == null) || strans.equals("")) { setTranslation(0); @@ -4052,6 +4093,26 @@ this.comment = comment; setMetaDataDirty(true); } + + public boolean isMinorEdit() + { + return isMinorEdit; + } + public void setMinorEdit(boolean isMinor) + { + this.isMinorEdit = isMinor; + setMetaDataDirty(true); + } + + // methods for easy table update. because default value == null + protected Boolean getMinorEdit1() + { + return Boolean.valueOf(isMinorEdit); + } + protected void setMinorEdit1(Boolean isMinor) + { + isMinorEdit = (isMinor!=null && isMinor.booleanValue()); + } public BaseObject newObject(String classname, XWikiContext context) throws XWikiException { Index: src/main/java/com/xpn/xwiki/doc/XWikiDocumentArchive.java =================================================================== --- src/main/java/com/xpn/xwiki/doc/XWikiDocumentArchive.java (revision 4044) +++ src/main/java/com/xpn/xwiki/doc/XWikiDocumentArchive.java (working copy) @@ -1,149 +1,311 @@ +/* + * Copyright 2006-2007, XpertNet SARL, and individual contributors as indicated + * by the contributors.txt. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ package com.xpn.xwiki.doc; +import java.util.Collection; +import java.util.Comparator; +import java.util.Date; +import java.util.Iterator; +import java.util.Set; +import java.util.SortedMap; +import java.util.SortedSet; +import java.util.TreeMap; +import java.util.TreeSet; + +import org.suigeneris.jrcs.diff.DifferentiationFailedException; +import org.suigeneris.jrcs.rcs.Version; +import org.suigeneris.jrcs.rcs.parse.ParseException; + +import com.xpn.xwiki.XWikiContext; import com.xpn.xwiki.XWikiException; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.apache.tools.ant.filters.StringInputStream; -import org.suigeneris.jrcs.rcs.Archive; -import org.suigeneris.jrcs.util.ToString; +import com.xpn.xwiki.doc.rcs.XWikiDiff; +import com.xpn.xwiki.doc.rcs.XWikiRCSArchive; +import com.xpn.xwiki.doc.rcs.XWikiRCSNodeContent; +import com.xpn.xwiki.doc.rcs.XWikiRCSNodeId; +import com.xpn.xwiki.doc.rcs.XWikiRCSNodeInfo; +import com.xpn.xwiki.plugin.packaging.PackagePlugin; -public class XWikiDocumentArchive { - private static final Log log = LogFactory.getLog(XWikiDocumentArchive.class); - +/** + * Contains document history. + * Allows to load any version of document. + * @version $Id: $ + */ +public class XWikiDocumentArchive +{ + /** =docId. */ private long id; - private Archive archive; - - public XWikiDocumentArchive() { + /** SortedMap from Version to XWikiRCSNodeInfo. */ + private SortedMap versionToNode = new TreeMap(); + /** SortedSet of Version - versions which has full document, not patch. */ + private SortedSet fullNodes = new TreeSet(); + + // store-specific information + /** Set of {@link XWikiRCSNodeInfo} which need to delete. */ + private Set deleteNodes = new TreeSet(); + /** Set of {@link XWikiRCSNodeInfo} which need to saveOrUpdate. */ + private Set updateNodeInfos = new TreeSet(new Comparator() { + public int compare(Object arg0, Object arg1) + { + XWikiRCSNodeInfo o1 = (XWikiRCSNodeInfo) arg0; + XWikiRCSNodeInfo o2 = (XWikiRCSNodeInfo) arg1; + return o1.getId().getVersion().compareTo(o2.getId().getVersion()); + } + }); + /** Set of {@link XWikiRCSNodeContent} which need to update. */ + private Set updateNodeContents = new TreeSet(new Comparator() { + public int compare(Object arg0, Object arg1) + { + XWikiRCSNodeContent o1 = (XWikiRCSNodeContent) arg0; + XWikiRCSNodeContent o2 = (XWikiRCSNodeContent) arg1; + return o1.getId().getVersion().compareTo(o2.getId().getVersion()); + } + }); + + // helper methods + /** + * @param cur - current version + * @param isMinor - is modification is minor + * @return next version + */ + protected Version getNextVersion(Version cur, boolean isMinor) { + if (!isMinor) { + return cur.getBase(1).next().newBranch(1); + } else { + return cur.next(); + } } + /** @param node - node added to versionToNode and fullNodes */ + protected void addNode(XWikiRCSNodeInfo node) { + versionToNode.put(node.getId().getVersion(), node); + if (!node.isPatch()) { + fullNodes.add(node.getId().getVersion()); + } + } + /** + * @param ver - version of new node + * @return new {@link XWikiRCSNodeId} constructing from getId() and ver + */ + protected XWikiRCSNodeId newNodeId(Version ver) { + return new XWikiRCSNodeId(getId(), ver); + } + /** + * @param latestnode - latest node in history (always full) + * @param curdoc - document from that diff created + * @param context - used for loading latestnode content + * @return new latestnode's content + * @throws DifferentiationFailedException if error then creating diff + * @throws XWikiException if error loading content + */ + protected XWikiRCSNodeContent makeDiffs(XWikiRCSNodeInfo latestnode, XWikiDocument curdoc, + XWikiContext context) throws DifferentiationFailedException, XWikiException + { + XWikiRCSNodeContent result = new XWikiRCSNodeContent(); + String text = curdoc.toXML(context); + result.setDelta( text ); + if (latestnode!=null) { + int nodescount = getNodes().size(); + int nodesperfull = context.getWiki()==null ? 5 : Integer.parseInt( + context.getWiki().getConfig().getProperty("xwiki.store.rcs.nodesPerFull", "5")); + if (nodesperfull<=0 || (nodescount%nodesperfull)!=0) { + XWikiRCSNodeContent latestcontent = latestnode.getContent(context); + latestcontent.setDelta( XWikiDiff.diff(text, latestcontent.getDelta()) ); + latestnode.setPatch(true); + fullNodes.remove(latestnode.getId().getVersion()); + } + } + return result; + } + /** @param id = {@link XWikiDocument#getId()} */ public XWikiDocumentArchive(long id) { setId(id); } - + /** @return {@link XWikiDocument#getId()} - primary key */ public long getId() { return id; } - + /** @param id = {@link XWikiDocument#getId()} */ public void setId(long id) { this.id = id; } - - public Archive getRCSArchive() { - return archive; + /** @return collection of XWikiRCSNodeInfo order by version desc */ + public Collection getNodes() { + return versionToNode.values(); } - - public void setRCSArchive(Archive archive) { - this.archive = archive; + /** @return collection of XWikiRCSNodeInfo where vfrom>=version>=vto order by version desc */ + public Collection getNodes(Version vfrom, Version vto) { + int[] ito = vto.getNumbers(); + ito[1]--; + return versionToNode.subMap(vfrom, new Version(ito)).values(); } - - public String getArchive() throws XWikiException { - if (archive == null) - return ""; - else { - StringBuffer buffer = new StringBuffer(); - archive.toString(buffer); - return buffer.toString(); + /** @param versions - collection of XWikiRCSNodeInfo */ + public void setNodes(Collection versions) { + resetArchive(); + for (Iterator it = versions.iterator(); it.hasNext(); ) + addNode((XWikiRCSNodeInfo) it.next()); + if (getNodes().size()>0) { + // ensure latest version is full + getLatestNode().setPatch(false); + fullNodes.add(getLatestNode().getId().getVersion()); } } - + /** + * @param context - used for load nodes content + * @return serialization of class + * used in {@link PackagePlugin}. + * @throws XWikiException if any error + */ + public String getArchive(XWikiContext context) throws XWikiException { + XWikiRCSArchive archive = new XWikiRCSArchive(getNodes(), context); + return archive.toString(); + } + /** + * Deserialize class. + * Used in {@link PackagePlugin}. + * @param text - archive in JRCS format + * @throws XWikiException if parse error + */ public void setArchive(String text) throws XWikiException { + XWikiRCSArchive archive; try { - if ((text!=null)&&(!text.trim().equals(""))) { - StringInputStream is = new StringInputStream(text); - archive = new Archive("", is); - } else - if (text == null){ - Object[] lines = new Object[1]; - lines[0] = ""; - archive = new Archive(lines, "", "1.0"); - } - else - { - Object[] lines = ToString.stringToArray(text); - archive = new Archive(lines, "", "1.0"); - } + archive = new XWikiRCSArchive(text); + } catch (ParseException e) { + throw new XWikiException(XWikiException.MODULE_XWIKI_DIFF, + XWikiException.ERROR_XWIKI_DIFF_CONTENT_ERROR, + "Exception while constructing document archive", e); } - catch (Exception e) { - Object[] args = { "" }; - throw new XWikiException(XWikiException.MODULE_XWIKI_STORE, XWikiException.ERROR_XWIKI_STORE_ARCHIVEFORMAT, - "Exception while manipulating the archive for doc {0}", e, args); + resetArchive(); + Collection nodes = archive.getNodes(getId()); + for (Iterator it=nodes.iterator(); it.hasNext(); ) { + XWikiRCSNodeInfo nodeinfo = (XWikiRCSNodeInfo) it.next(); + XWikiRCSNodeContent nodecontent = (XWikiRCSNodeContent) it.next(); + addNode(nodeinfo); + updateNodeInfos.add(nodeinfo); + updateNodeContents.add(nodecontent); } } - - public void updateArchive(String docname, String text) throws XWikiException { - - // JRCS used the user.name System property to set the author of a change. However JRCS - // has a bug when the user name has a space in the name - // (see http://www.suigeneris.org/issues/browse/JRCS-22). The workaround is to set the - // user.name System property to some user without a space in its name. In addition - // we're not using that information anywhere so it won't matter. When JRCS bug is fixed - // remove this hack. - - // Saving the property in case some other part of the code or some dependent framework - // needs it. - String originalUsername = System.getProperty("user.name"); - - System.setProperty("user.name", "xwiki"); - + /** + * Update history with new document version + * @param author - author of version + * @param date - date of version + * @param comment - version comment + * @param isMinor - is minor version + * @param curdoc - document for this version + * @param context - used for loading nodes content + * @throws XWikiException in any error + */ + public void updateArchive(String author, Date date, String comment, boolean isMinor, + XWikiDocument curdoc, XWikiContext context) throws XWikiException + { try { - Object[] lines = ToString.stringToArray(text); - if (archive != null) - archive.addRevision(lines, ""); - else - archive = new Archive(lines, docname, "1.0"); + if (versionToNode.size()>0) { + XWikiRCSNodeInfo orignode = getLatestNode(); + + XWikiRCSNodeInfo newnode = new XWikiRCSNodeInfo(); + newnode.setId(newNodeId(getNextVersion(orignode.getId().getVersion(), isMinor))); + newnode.setComment(comment); + newnode.setAuthor(author); + newnode.setDate(date); + + XWikiRCSNodeContent origcontent = orignode.getContent(context); + XWikiRCSNodeContent newcontent = makeDiffs(orignode, curdoc, context); + newnode.setContent(newcontent); + newnode.setPatch(false); + + addNode(newnode); + updateNodeInfos.add(newnode); + updateNodeContents.add(newcontent); + if (orignode.isPatch()) { + updateNodeInfos.add(orignode); + updateNodeContents.add(origcontent); + } + } else { + XWikiRCSNodeInfo newnode = new XWikiRCSNodeInfo( + new XWikiRCSNodeId(id, new Version(1,1))); + newnode.setAuthor(author); + newnode.setDate(date); + newnode.setComment(comment); + XWikiRCSNodeContent newcontent = makeDiffs(null, curdoc, context); + newnode.setContent(newcontent); + newnode.setPatch(false); + addNode(newnode); + updateNodeInfos.add(newnode); + updateNodeContents.add(newcontent); + } + } catch (DifferentiationFailedException e) { + Object[] args = new Object[]{Long.valueOf(getId())}; + throw new XWikiException(XWikiException.MODULE_XWIKI_DIFF, + XWikiException.ERROR_XWIKI_DIFF_CONTENT_ERROR, + "Exception while updateArchive for docId={}", e, args); } - catch (Exception e) { - Object[] args = { docname }; - throw new XWikiException(XWikiException.MODULE_XWIKI_STORE, XWikiException.ERROR_XWIKI_STORE_ARCHIVEFORMAT, - "Exception while manipulating the archive for doc {0}", e, args); - } finally { - // Restore the user name to its original value - System.setProperty("user.name", originalUsername); - } - } - - public Object clone() { - XWikiDocumentArchive docarchive = null; - try { - docarchive = (XWikiDocumentArchive) getClass().newInstance(); - } catch (Exception e) { - // This should not happen - } - - docarchive.setId(getId()); - docarchive.setRCSArchive(getRCSArchive()); - return docarchive; + /** + * @return {@link XWikiRCSNodeInfo} by version + * @param version which version to get + */ + public XWikiRCSNodeInfo getNode(Version version) + { + return (XWikiRCSNodeInfo) versionToNode.get(version); } - - - public boolean equals(Object object) { - XWikiDocumentArchive doc = (XWikiDocumentArchive) object; - if (getId()!=doc.getId()) - return false; - - try { - if (!getArchive().equals(doc.getArchive())) - return false; - } catch (XWikiException e) { - return false; - } - - return true; + /** @return latest version in history for document */ + public Version getLatestVersion() + { + return (Version) versionToNode.firstKey(); } - - public void resetArchive(String docname, String text, String version) throws XWikiException { - Object[] lines = ToString.stringToArray(text); - archive = new Archive(lines, docname, version); + /** @return latest node in history for document */ + public XWikiRCSNodeInfo getLatestNode() { + return getNode( getLatestVersion() ); } - - /** - * {@inheritDoc} - * @see Object#toString() + /** + * @param ver - version for what nearest + * @return nearest version which contain full information (not patch) */ - public String toString() + public Version getNearestFullVersion(Version ver) { + if (fullNodes.contains(ver)) + return ver; + return (Version) fullNodes.headSet(ver).last(); + // latest node is always full + } + /** reset history. history becomes empty. */ + public void resetArchive() { - return "id = [" + getId() + "], archive = [" - + (getRCSArchive() == null ? "null" : getRCSArchive().toString()) + "]"; + versionToNode.clear(); + deleteNodes.addAll(updateNodeInfos); + updateNodeInfos.clear(); + updateNodeContents.clear(); } + + /** @return mutable Set of {@link XWikiRCSNodeInfo} which are need for delete */ + public Set getDeleteNodeInfo() + { + return deleteNodes; + } + /** @return mutable Set of {@link XWikiRCSNodeInfo} which are need for saveOrUpdate */ + public Set getUpdeteNodeInfos() + { + return updateNodeInfos; + } + /** @return mutable Set of {@link XWikiRCSNodeContent} which are need for update */ + public Set getUpdeteNodeContents() + { + return updateNodeContents; + } } Index: src/main/java/com/xpn/xwiki/api/RevisionInfo.java =================================================================== --- src/main/java/com/xpn/xwiki/api/RevisionInfo.java (revision 0) +++ src/main/java/com/xpn/xwiki/api/RevisionInfo.java (revision 0) @@ -0,0 +1,69 @@ +/* + * Copyright 2007, XpertNet SARL, and individual contributors as indicated + * by the contributors.txt. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ +package com.xpn.xwiki.api; + +import java.util.Date; + +import com.xpn.xwiki.XWikiContext; +import com.xpn.xwiki.doc.rcs.XWikiRCSNodeInfo; + +/** + * API object for get info about some version of Document. + * @version $Id: $ + */ +public class RevisionInfo extends Api +{ + /** used for get all information. */ + private XWikiRCSNodeInfo nodeInfo; + /** + * @param nodeInfo - from that nodeinfo all information is getting + * @param context - needed for {@link Api} + */ + public RevisionInfo(XWikiRCSNodeInfo nodeInfo, XWikiContext context) + { + super(context); + this.nodeInfo = nodeInfo; + } + /** @return version of this revision */ + public String getVersion() + { + return nodeInfo.getId().getVersion().toString(); + } + /** @return date of this revision */ + public Date getDate() + { + return nodeInfo.getDate(); + } + /** @return author of this revision */ + public String getAuthor() + { + return nodeInfo.getAuthor(); + } + /** @return revision comment */ + public String getComment() + { + return nodeInfo.getComment(); + } + /** @return is revision is minor */ + public boolean isMinorEdit() { + return nodeInfo.isMinorEdit(); + } +} Property changes on: src/main/java/com/xpn/xwiki/api/RevisionInfo.java ___________________________________________________________________ Name: svn:eol-style + native Index: src/main/java/com/xpn/xwiki/api/XWiki.java =================================================================== --- src/main/java/com/xpn/xwiki/api/XWiki.java (revision 4044) +++ src/main/java/com/xpn/xwiki/api/XWiki.java (working copy) @@ -34,7 +34,7 @@ import com.xpn.xwiki.stats.impl.DocumentStats; import com.xpn.xwiki.web.Utils; import com.xpn.xwiki.web.XWikiEngineContext; -import org.suigeneris.jrcs.diff.Chunk; +import org.suigeneris.jrcs.diff.delta.Chunk; import java.awt.image.BufferedImage; import java.io.IOException; @@ -2320,6 +2320,14 @@ { return xwiki.isEditCommentMandatory(context); } + + /** + * API to check if the minor edit feature is active + * minor edit are activated in xwiki.cfg or in the XWiki Preferences + */ + public boolean hasMinorEdit() { + return xwiki.hasMinorEdit(context); + } /** * API to rename a page (experimental) Rights are necessary to edit the source and target page Index: src/main/java/com/xpn/xwiki/api/Document.java =================================================================== --- src/main/java/com/xpn/xwiki/api/Document.java (revision 4044) +++ src/main/java/com/xpn/xwiki/api/Document.java (working copy) @@ -280,6 +280,11 @@ { return doc.getComment(); } + + public boolean isMinorEdit() + { + return doc.isMinorEdit(); + } /** * return the list of possible traduction for this document @@ -354,7 +359,7 @@ */ public String getArchive() throws XWikiException { - return doc.getDocumentArchive(getXWikiContext()).getArchive(); + return doc.getDocumentArchive(getXWikiContext()).getArchive(getXWikiContext()); } /** @@ -680,6 +685,10 @@ { return doc.getRecentRevisions(nb, getXWikiContext()); } + + public RevisionInfo getRevisionInfo(String version) throws XWikiException { + return new RevisionInfo( doc.getRevisionInfo(version, getXWikiContext()), getXWikiContext() ); + } public List getAttachmentList() { @@ -1398,6 +1407,10 @@ { getDoc().setComment(comment); } + + public void setMinorEdit(boolean isMinor) { + getDoc().setMinorEdit(isMinor); + } public void save() throws XWikiException { Index: src/main/java/com/xpn/xwiki/XWiki.java =================================================================== --- src/main/java/com/xpn/xwiki/XWiki.java (revision 4044) +++ src/main/java/com/xpn/xwiki/XWiki.java (working copy) @@ -939,8 +939,14 @@ // If no comment is provided we should use an empty comment saveDocument(doc, "", context); } + + public void saveDocument(XWikiDocument doc, String comment, XWikiContext context) + throws XWikiException + { + saveDocument(doc, comment, false, context); + } - public void saveDocument(XWikiDocument doc, String comment, XWikiContext context) + public void saveDocument(XWikiDocument doc, String comment, boolean isMinorEdit, XWikiContext context) throws XWikiException { String server = null, database = null; @@ -954,6 +960,7 @@ // Setting comment before saving doc.setComment((comment == null) ? "" : comment); + doc.setMinorEdit(isMinorEdit); getStore().saveXWikiDoc(doc, context); @@ -4937,6 +4944,16 @@ return false; return "1".equals(Param("xwiki.editcomment.mandatory", "0")); } + + public boolean hasMinorEdit(XWikiContext context) + { + String bl = getXWikiPreference("minoredit", "", context); + if ("1".equals(bl)) + return true; + if ("0".equals(bl)) + return false; + return "1".equals(Param("xwiki.minoredit", "1")); + } /** * @deprecated use {@link XWikiDocument#rename(String, XWikiContext)} instead Index: src/main/java/com/xpn/xwiki/web/EditForm.java =================================================================== --- src/main/java/com/xpn/xwiki/web/EditForm.java (revision 4044) +++ src/main/java/com/xpn/xwiki/web/EditForm.java (working copy) @@ -50,11 +50,13 @@ private String title; private String comment; + + private boolean isMinorEdit = false; private String tags; private boolean lockForce; - + public void readRequest() { XWikiRequest request = getRequest(); @@ -71,6 +73,7 @@ setDefaultLanguage(request.getParameter("default_language")); setTags(request.getParameterValues("tags")); setLockForce("1".equals(request.getParameter("force"))); + setMinorEdit(request.getParameter("minor_edit")!=null); } public void setTags(String[] parameter) @@ -231,6 +234,16 @@ { this.comment = comment; } + + public boolean isMinorEdit() + { + return isMinorEdit; + } + + public void setMinorEdit(boolean isMinorEdit) + { + this.isMinorEdit = isMinorEdit; + } public boolean isLockForce() { Index: src/main/java/com/xpn/xwiki/web/CommentAddAction.java =================================================================== --- src/main/java/com/xpn/xwiki/web/CommentAddAction.java (revision 4044) +++ src/main/java/com/xpn/xwiki/web/CommentAddAction.java (working copy) @@ -55,7 +55,7 @@ newobject.setNumber(oldobject.getNumber()); newobject.setName(doc.getFullName()); doc.setObject(className, nb, newobject); - xwiki.saveDocument(doc, context.getMessageTool().get("core.comment.addComment"), context); + xwiki.saveDocument(doc, context.getMessageTool().get("core.comment.addComment"), true, context); } // forward to edit String redirect = Utils.getRedirect("edit", context); Index: src/main/java/com/xpn/xwiki/web/ObjectRemoveAction.java =================================================================== --- src/main/java/com/xpn/xwiki/web/ObjectRemoveAction.java (revision 4044) +++ src/main/java/com/xpn/xwiki/web/ObjectRemoveAction.java (working copy) @@ -43,7 +43,7 @@ objects.set(classId, null); doc.addObjectsToRemove(object); doc.setAuthor(context.getUser()); - xwiki.saveDocument(doc, context.getMessageTool().get("core.comment.deleteObject"), context); + xwiki.saveDocument(doc, context.getMessageTool().get("core.comment.deleteObject"), true, context); // forward to edit String redirect = Utils.getRedirect("edit", context); Index: src/main/java/com/xpn/xwiki/web/SaveAction.java =================================================================== --- src/main/java/com/xpn/xwiki/web/SaveAction.java (revision 4044) +++ src/main/java/com/xpn/xwiki/web/SaveAction.java (working copy) @@ -95,6 +95,7 @@ tdoc.setContent(content); tdoc.setTitle(title); tdoc.setComment(sectionDoc.getComment()); + tdoc.setMinorEdit(sectionDoc.isMinorEdit()); }else{ tdoc.readFromForm((EditForm) form, context); } @@ -110,7 +111,7 @@ // We get the comment to be used from the document // It was read using readFromForm - xwiki.saveDocument(tdoc, tdoc.getComment(), context); + xwiki.saveDocument(tdoc, tdoc.getComment(), tdoc.isMinorEdit(), context); XWikiLock lock = tdoc.getLock(context); if (lock != null) tdoc.removeLock(context); Index: src/main/java/com/xpn/xwiki/web/PropAddAction.java =================================================================== --- src/main/java/com/xpn/xwiki/web/PropAddAction.java (revision 4044) +++ src/main/java/com/xpn/xwiki/web/PropAddAction.java (working copy) @@ -62,7 +62,7 @@ if (doc.isNew()) { doc.setCreator(username); } - xwiki.saveDocument(doc, context.getMessageTool().get("core.comment.addClassProperty"), context); + xwiki.saveDocument(doc, context.getMessageTool().get("core.comment.addClassProperty"), true, context); } } // forward to edit Index: src/main/java/com/xpn/xwiki/web/ObjectAddAction.java =================================================================== --- src/main/java/com/xpn/xwiki/web/ObjectAddAction.java (revision 4044) +++ src/main/java/com/xpn/xwiki/web/ObjectAddAction.java (working copy) @@ -63,7 +63,7 @@ if (doc.isNew()) { doc.setCreator(username); } - xwiki.saveDocument(doc, context.getMessageTool().get("core.comment.addObject"), context); + xwiki.saveDocument(doc, context.getMessageTool().get("core.comment.addObject"), true, context); // forward to edit String redirect = Utils.getRedirect("edit", context); Index: src/main/java/com/xpn/xwiki/web/PropUpdateAction.java =================================================================== --- src/main/java/com/xpn/xwiki/web/PropUpdateAction.java (revision 4044) +++ src/main/java/com/xpn/xwiki/web/PropUpdateAction.java (working copy) @@ -75,7 +75,7 @@ doc.setxWikiClass(bclass2); doc.renameProperties(bclass.getName(), fieldsToRename); - xwiki.saveDocument(doc, context.getMessageTool().get("core.comment.updateClassProperty"), context); + xwiki.saveDocument(doc, context.getMessageTool().get("core.comment.updateClassProperty"), true, context); // We need to load all documents that use this property and rename it if (fieldsToRename.size() > 0) { @@ -88,7 +88,7 @@ for (int i = 0; i < list.size(); i++) { XWikiDocument doc2 = xwiki.getDocument((String) list.get(i), context); doc2.renameProperties(bclass.getName(), fieldsToRename); - xwiki.saveDocument(doc2, context.getMessageTool().get("core.comment.updateClassPropertyName"), context); + xwiki.saveDocument(doc2, context.getMessageTool().get("core.comment.updateClassPropertyName"), true, context); } } xwiki.flushCache(); Index: src/main/resources/ApplicationResources.properties =================================================================== --- src/main/resources/ApplicationResources.properties (revision 4044) +++ src/main/resources/ApplicationResources.properties (working copy) @@ -702,6 +702,10 @@ core.comment.rollback=Rollback to version {0} core.comment.updateContent=Update Content +core.minoredit=Is minor edit +core.minoredit.show=Show minor edits +core.minoredit.hide=Hide minor edits + # top menu core.menu.documentation=Documentation core.menu.create=Create Index: src/main/resources/xwiki.derby.hbm.xml =================================================================== --- src/main/resources/xwiki.derby.hbm.xml (revision 4044) +++ src/main/resources/xwiki.derby.hbm.xml (working copy) @@ -107,17 +107,33 @@ + + + - - - - - - - - + + + + + + + + + + + + + + + + + + + + + Index: src/main/resources/xwiki.oracle.hbm.xml =================================================================== --- src/main/resources/xwiki.oracle.hbm.xml (revision 4044) +++ src/main/resources/xwiki.oracle.hbm.xml (working copy) @@ -101,17 +101,33 @@ + + + - - - - - - - - + + + + + + + + + + + + + + + + + + + + + Index: src/main/resources/xwiki.hbm.xml =================================================================== --- src/main/resources/xwiki.hbm.xml (revision 4044) +++ src/main/resources/xwiki.hbm.xml (working copy) @@ -99,17 +99,30 @@ + + + - - - - - - - - + + + + + + + + + + + + + + + + + + Index: pom.xml =================================================================== --- pom.xml (revision 4044) +++ pom.xml (working copy) @@ -83,13 +83,13 @@ org.suigeneris jrcs.diff - 0.3.0 + 0.4.1 xwiki org.suigeneris jrcs.rcs - 0.3.0 + 0.4.1 xwiki @@ -519,7 +519,11 @@ **/content/**/*.java, **/XWikiMessageTool.java, **/XWikiListFilter.java, - **/MyPersistentLoginManager.java + **/MyPersistentLoginManager.java, + **/XWikiRCS*.java, + **/RevisionInfo.java + **/RenamePageReplaceLinkHandler.java @@ -560,4 +564,4 @@ - \ No newline at end of file +