1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34 package info.magnolia.pages.app.editor;
35
36 import info.magnolia.cms.core.Path;
37 import info.magnolia.context.Context;
38 import info.magnolia.jcr.util.NodeTypes;
39 import info.magnolia.jcr.util.NodeTypes.Renderable;
40 import info.magnolia.ui.framework.ContentClipboard;
41 import info.magnolia.ui.framework.ContentClipboardException;
42 import info.magnolia.ui.vaadin.gwt.client.shared.AbstractElement;
43 import info.magnolia.ui.vaadin.gwt.client.shared.AreaElement;
44 import info.magnolia.ui.vaadin.gwt.client.shared.ComponentElement;
45
46 import java.text.MessageFormat;
47 import java.util.ArrayList;
48 import java.util.Arrays;
49 import java.util.List;
50
51 import javax.inject.Inject;
52 import javax.inject.Provider;
53 import javax.jcr.ItemNotFoundException;
54 import javax.jcr.Node;
55 import javax.jcr.NodeIterator;
56 import javax.jcr.PathNotFoundException;
57 import javax.jcr.RepositoryException;
58 import javax.jcr.Session;
59
60 import org.apache.commons.lang3.StringUtils;
61 import org.slf4j.Logger;
62 import org.slf4j.LoggerFactory;
63
64
65
66
67
68 public class ComponentContentClipboard implements ContentClipboard<AbstractElement> {
69
70 private static final Logger log = LoggerFactory.getLogger(ComponentContentClipboard.class);
71
72 private static final String AVAILABLE_COMPONENTS_DIVIDER = ",";
73
74 private final Provider<Context> contextProvider;
75 private List<AbstractElement> items = new ArrayList<>();
76
77 @Inject
78 public ComponentContentClipboard(Provider<Context> contextProvider) {
79 this.contextProvider = contextProvider;
80 }
81
82 @Override
83 public void copy(final List<AbstractElement> source) {
84 List<AbstractElement> newItems = new ArrayList<>();
85 for (AbstractElement sourceItem : source) {
86 try {
87 Session session = contextProvider.get().getJCRSession(sourceItem.getWorkspace());
88
89 if (sourceItem instanceof ComponentElement) {
90 newItems.add(sourceItem);
91 } else if (sourceItem instanceof AreaElement) {
92
93 Node areaNode = session.getNode(sourceItem.getPath());
94 NodeIterator nit = areaNode.getNodes();
95 while (nit.hasNext()) {
96 Node componentNode = nit.nextNode();
97 if (StringUtils.equals(componentNode.getPrimaryNodeType().getName(), NodeTypes.Component.NAME)) {
98 newItems.add(new ComponentElement(componentNode.getSession().getWorkspace().getName(), componentNode.getPath(), null));
99 }
100 }
101 }
102 } catch (RepositoryException e) {
103 throw new ContentClipboardException(MessageFormat.format("Failed while copying element [{0}] from [{1}] workspace.", sourceItem.getPath(), sourceItem.getWorkspace()), e);
104 }
105 }
106 this.items = newItems;
107 }
108
109
110
111
112 @Override
113 public List<AbstractElement> paste(final AbstractElement destination) {
114 List<AbstractElement> pastedElements = new ArrayList<>();
115
116 try {
117 final Session session = contextProvider.get().getJCRSession(destination.getWorkspace());
118 final Node areaNode = session.getNode(destination.getPath());
119 for (AbstractElement element : items) {
120 Node componentNode = session.getNode(element.getPath());
121 AbstractElement duplicatedElement = copyComponent(areaNode, componentNode);
122 pastedElements.add(duplicatedElement);
123 }
124 } catch (RepositoryException e) {
125 throw new ContentClipboardException(MessageFormat.format("Failed while pasting content of clipboard under element [{0}] from [{1}] workspace.", destination.getPath(), destination.getWorkspace()), e);
126 }
127 return pastedElements;
128 }
129
130 @Override
131 public boolean canCopy(final List<AbstractElement> source) {
132 try {
133 boolean result = true;
134 for (AbstractElement element : source) {
135 Session session = contextProvider.get().getJCRSession(element.getWorkspace());
136
137 if (element instanceof AreaElement) {
138 Node areaNode = session.getNode(element.getPath());
139 result = result && hasOnlyChildComponents(areaNode);
140
141
142 if (!result) {
143 return false;
144 }
145 }
146 }
147 return result;
148 } catch (RepositoryException e) {
149 log.warn("Problem while checking whether an item can be copied.", e);
150 return false;
151 }
152 }
153
154 @Override
155 public boolean canPasteInto(final AbstractElement destination) {
156 try {
157 Session session = contextProvider.get().getJCRSession(destination.getWorkspace());
158 boolean result = items.size() > 0;
159 if (destination instanceof AreaElement) {
160 List<String> availableComponents = Arrays.asList(((AreaElement) destination).getAvailableComponents().split(AVAILABLE_COMPONENTS_DIVIDER));
161 for (AbstractElement source : items) {
162 if (source instanceof ComponentElement) {
163 Node componentNode = session.getNode(source.getPath());
164 String templateId = Renderable.getTemplate(componentNode);
165 result = result && availableComponents.contains(templateId);
166
167
168 if (!result) {
169 return false;
170 }
171 }
172 }
173 return result;
174 }
175 } catch (PathNotFoundException | ItemNotFoundException e) {
176 log.warn("Problem while checking availability. One of the copied components was deleted.", e);
177 } catch (RepositoryException e) {
178 log.warn("Problem while checking availability.", e);
179 }
180 return false;
181 }
182
183 private AbstractElement copyComponent(Node areaNode, Node componentNode) throws RepositoryException {
184 final String newName = getUniqueNewItemName(areaNode, componentNode.getName());
185 final String newPath = Path.getAbsolutePath(areaNode.getPath(), newName);
186
187 componentNode.getSession().getWorkspace().copy(componentNode.getPath(), newPath);
188
189 final Node duplicateNode = componentNode.getSession().getNode(newPath);
190 return new ComponentElement(duplicateNode.getSession().getWorkspace().getName(), duplicateNode.getPath(), null);
191 }
192
193 private String getUniqueNewItemName(Node parent, String name) throws RepositoryException {
194 return Path.getUniqueLabel(parent.getSession(), parent.getPath(), name);
195 }
196
197
198
199
200 private boolean hasOnlyChildComponents(Node areaNode) throws RepositoryException {
201 boolean result = false;
202 NodeIterator nit = areaNode.getNodes();
203 if (nit.hasNext()) {
204 result = true;
205 while (nit.hasNext()) {
206 Node node = nit.nextNode();
207 if (!NodeTypes.Component.NAME.equals(node.getPrimaryNodeType().getName())) {
208 result = false;
209 break;
210 }
211 }
212 }
213 return result;
214 }
215
216 }