2 * Copyright 2000-2009 JetBrains s.r.o.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
16 package com
.intellij
.openapi
.vcs
.changes
.ui
;
18 import com
.intellij
.ide
.util
.PropertiesComponent
;
19 import com
.intellij
.openapi
.Disposable
;
20 import com
.intellij
.openapi
.extensions
.Extensions
;
21 import com
.intellij
.openapi
.actionSystem
.AnAction
;
22 import com
.intellij
.openapi
.actionSystem
.DataKey
;
23 import com
.intellij
.openapi
.actionSystem
.DataSink
;
24 import com
.intellij
.openapi
.actionSystem
.TypeSafeDataProvider
;
25 import com
.intellij
.openapi
.application
.ModalityState
;
26 import com
.intellij
.openapi
.fileEditor
.FileDocumentManager
;
27 import com
.intellij
.openapi
.progress
.ProgressManager
;
28 import com
.intellij
.openapi
.project
.Project
;
29 import com
.intellij
.openapi
.ui
.*;
30 import com
.intellij
.openapi
.util
.Comparing
;
31 import com
.intellij
.openapi
.util
.Disposer
;
32 import com
.intellij
.openapi
.util
.Ref
;
33 import com
.intellij
.openapi
.util
.text
.StringUtil
;
34 import com
.intellij
.openapi
.vcs
.*;
35 import com
.intellij
.openapi
.vcs
.changes
.*;
36 import com
.intellij
.openapi
.vcs
.changes
.actions
.ShowDiffAction
;
37 import com
.intellij
.openapi
.vcs
.checkin
.*;
38 import com
.intellij
.openapi
.vcs
.ui
.CommitMessage
;
39 import com
.intellij
.openapi
.vcs
.ui
.RefreshableOnComponent
;
40 import com
.intellij
.openapi
.vfs
.VirtualFile
;
41 import com
.intellij
.ui
.IdeBorderFactory
;
42 import com
.intellij
.ui
.SeparatorFactory
;
43 import com
.intellij
.util
.Alarm
;
44 import org
.jetbrains
.annotations
.NonNls
;
45 import org
.jetbrains
.annotations
.NotNull
;
46 import org
.jetbrains
.annotations
.Nullable
;
50 import java
.awt
.event
.ActionEvent
;
53 import java
.util
.List
;
58 public class CommitChangeListDialog
extends DialogWrapper
implements CheckinProjectPanel
, TypeSafeDataProvider
{
59 private final CommitMessage myCommitMessageArea
;
60 private Splitter mySplitter
;
61 private final JPanel myAdditionalOptionsPanel
;
63 private final ChangesBrowser myBrowser
;
64 private final ChangesBrowserExtender myBrowserExtender
;
66 private CommitLegendPanel myLegend
;
68 private final List
<RefreshableOnComponent
> myAdditionalComponents
= new ArrayList
<RefreshableOnComponent
>();
69 private final List
<CheckinHandler
> myHandlers
= new ArrayList
<CheckinHandler
>();
70 private final String myActionName
;
71 private final Project myProject
;
72 private final List
<CommitExecutor
> myExecutors
;
73 private final Alarm myOKButtonUpdateAlarm
= new Alarm(Alarm
.ThreadToUse
.SWING_THREAD
);
74 private String myLastKnownComment
= "";
75 private final boolean myAllOfDefaultChangeListChangesIncluded
;
76 @NonNls private static final String SPLITTER_PROPORTION_OPTION
= "CommitChangeListDialog.SPLITTER_PROPORTION";
77 private final Action
[] myExecutorActions
;
78 private final boolean myShowVcsCommit
;
79 private final Map
<AbstractVcs
, JPanel
> myPerVcsOptionsPanels
= new HashMap
<AbstractVcs
, JPanel
>();
82 private final AbstractVcs myVcs
;
83 private final boolean myIsAlien
;
84 private boolean myDisposed
= false;
85 private final JLabel myWarningLabel
;
87 private final Map
<String
, CheckinChangeListSpecificComponent
> myCheckinChangeListSpecificComponents
;
89 private final Map
<String
, String
> myListComments
;
90 private String myLastSelectedListName
;
92 private static class MyUpdateButtonsRunnable
implements Runnable
{
93 private CommitChangeListDialog myDialog
;
95 private MyUpdateButtonsRunnable(final CommitChangeListDialog dialog
) {
99 public void cancel() {
104 if (myDialog
!= null) {
105 myDialog
.updateButtons();
106 myDialog
.updateLegend();
110 public void restart(final CommitChangeListDialog dialog
) {
116 private final MyUpdateButtonsRunnable myUpdateButtonsRunnable
= new MyUpdateButtonsRunnable(this);
118 private static boolean commit(final Project project
, final List
<Change
> changes
, final LocalChangeList initialSelection
,
119 final List
<CommitExecutor
> executors
, final boolean showVcsCommit
, final String comment
) {
120 final ChangeListManager manager
= ChangeListManager
.getInstance(project
);
121 final LocalChangeList defaultList
= manager
.getDefaultChangeList();
122 final ArrayList
<LocalChangeList
> changeLists
= new ArrayList
<LocalChangeList
>(manager
.getChangeListsCopy());
123 CommitChangeListDialog dialog
=
124 new CommitChangeListDialog(project
, changes
, initialSelection
, executors
, showVcsCommit
, defaultList
, changeLists
, null, false,
127 return dialog
.isOK();
130 public static void commitPaths(final Project project
, Collection
<FilePath
> paths
, final LocalChangeList initialSelection
,
131 @Nullable final CommitExecutor executor
, final String comment
) {
132 final ChangeListManager manager
= ChangeListManager
.getInstance(project
);
133 final Collection
<Change
> changes
= new HashSet
<Change
>();
134 for (FilePath path
: paths
) {
135 changes
.addAll(manager
.getChangesIn(path
));
138 commitChanges(project
, changes
, initialSelection
, executor
, comment
);
141 public static boolean commitChanges(final Project project
, final Collection
<Change
> changes
, final LocalChangeList initialSelection
,
142 final CommitExecutor executor
, final String comment
) {
143 final ChangeListManager manager
= ChangeListManager
.getInstance(project
);
144 if (executor
== null) {
145 return commitChanges(project
, changes
, initialSelection
, manager
.getRegisteredExecutors(), true, comment
);
148 return commitChanges(project
, changes
, initialSelection
, Collections
.singletonList(executor
), false, comment
);
152 public static boolean commitChanges(final Project project
, final Collection
<Change
> changes
, final LocalChangeList initialSelection
,
153 final List
<CommitExecutor
> executors
, final boolean showVcsCommit
, final String comment
) {
154 if (changes
.isEmpty()) {
155 Messages
.showWarningDialog(project
, VcsBundle
.message("commit.dialog.no.changes.detected.text") ,
156 VcsBundle
.message("commit.dialog.no.changes.detected.title"));
160 return commit(project
, new ArrayList
<Change
>(changes
), initialSelection
, executors
, showVcsCommit
, comment
);
163 public static void commitAlienChanges(final Project project
, final List
<Change
> changes
, final AbstractVcs vcs
,
164 final String changelistName
, final String comment
) {
165 final LocalChangeList lcl
= new AlienLocalChangeList(changes
, changelistName
);
166 new CommitChangeListDialog(project
, changes
, null, null, true, AlienLocalChangeList
.DEFAULT_ALIEN
, Collections
.singletonList(lcl
), vcs
,
167 true, comment
).show();
170 private CommitChangeListDialog(final Project project
,
171 final List
<Change
> changes
,
172 final LocalChangeList initialSelection
,
173 final List
<CommitExecutor
> executors
,
174 final boolean showVcsCommit
, final LocalChangeList defaultChangeList
,
175 final List
<LocalChangeList
> changeLists
, final AbstractVcs singleVcs
, final boolean isAlien
,
176 final String comment
) {
177 super(project
, true);
179 myExecutors
= executors
;
180 myShowVcsCommit
= showVcsCommit
;
182 myListComments
= new HashMap
<String
, String
>();
184 if (!myShowVcsCommit
&& ((myExecutors
== null) || myExecutors
.size() == 0)) {
185 throw new IllegalArgumentException("nothing found to execute commit with");
188 myAllOfDefaultChangeListChangesIncluded
= changes
.containsAll(defaultChangeList
.getChanges());
192 AlienChangeListBrowser browser
= new AlienChangeListBrowser(project
, changeLists
, changes
, initialSelection
, true, true, singleVcs
);
194 myBrowserExtender
= browser
;
196 MultipleChangeListBrowser browser
= new MultipleChangeListBrowser(project
, changeLists
, changes
, initialSelection
, true, true,
204 for (CheckinHandler handler
: myHandlers
) {
205 handler
.includedChangesChanged();
210 myBrowserExtender
= browser
.getExtender();
213 myBrowserExtender
.addToolbarActions(this);
215 myBrowserExtender
.addSelectedListChangeListener(new SelectedListChangeListener() {
216 public void selectedListChanged() {
217 updateOnListSelection();
220 myBrowser
.setDiffExtendUIFactory(new ShowDiffAction
.DiffExtendUIFactory() {
221 public List
<?
extends AnAction
> createActions(final Change change
) {
222 return myBrowser
.createDiffActions(change
);
226 public JComponent
createBottomComponent() {
227 return new DiffCommitMessageEditor(CommitChangeListDialog
.this);
231 myCommitMessageArea
= new CommitMessage();
232 myCommitMessageArea
.init();
234 if (comment
!= null) {
235 setCommitMessage(comment
);
236 myLastKnownComment
= comment
;
237 myLastSelectedListName
= initialSelection
== null ?
null : initialSelection
.getName();
239 setCommitMessage(VcsConfiguration
.getInstance(project
).LAST_COMMIT_MESSAGE
);
242 String messageFromVcs
= getInitialMessageFromVcs();
243 if (messageFromVcs
!= null) {
244 myCommitMessageArea
.setText(messageFromVcs
);
248 myActionName
= VcsBundle
.message("commit.dialog.title");
250 myAdditionalOptionsPanel
= new JPanel();
252 myAdditionalOptionsPanel
.setLayout(new BorderLayout());
253 Box optionsBox
= Box
.createVerticalBox();
255 boolean hasVcsOptions
= false;
256 Box vcsCommitOptions
= Box
.createVerticalBox();
257 final List
<AbstractVcs
> vcses
= getAffectedVcses();
258 myCheckinChangeListSpecificComponents
= new HashMap
<String
, CheckinChangeListSpecificComponent
>();
259 for (AbstractVcs vcs
: vcses
) {
260 final CheckinEnvironment checkinEnvironment
= vcs
.getCheckinEnvironment();
261 if (checkinEnvironment
!= null) {
262 final RefreshableOnComponent options
= checkinEnvironment
.createAdditionalOptionsPanel(this);
263 if (options
!= null) {
264 JPanel vcsOptions
= new JPanel(new BorderLayout());
265 vcsOptions
.add(options
.getComponent(), BorderLayout
.CENTER
);
266 vcsOptions
.add(SeparatorFactory
.createSeparator(vcs
.getDisplayName(), null), BorderLayout
.NORTH
);
267 vcsCommitOptions
.add(vcsOptions
);
268 myPerVcsOptionsPanels
.put(vcs
, vcsOptions
);
269 myAdditionalComponents
.add(options
);
270 if (options
instanceof CheckinChangeListSpecificComponent
) {
271 myCheckinChangeListSpecificComponents
.put(vcs
.getName(), (CheckinChangeListSpecificComponent
) options
);
273 hasVcsOptions
= true;
279 vcsCommitOptions
.add(Box
.createVerticalGlue());
280 optionsBox
.add(vcsCommitOptions
);
283 boolean beforeVisible
= false;
284 boolean afterVisible
= false;
285 Box beforeBox
= Box
.createVerticalBox();
286 Box afterBox
= Box
.createVerticalBox();
287 final List
<CheckinHandlerFactory
> handlerFactories
= ProjectLevelVcsManager
.getInstance(project
).getRegisteredCheckinHandlerFactories();
288 for (CheckinHandlerFactory factory
: handlerFactories
) {
289 final CheckinHandler handler
= factory
.createHandler(this);
290 myHandlers
.add(handler
);
291 final RefreshableOnComponent beforePanel
= handler
.getBeforeCheckinConfigurationPanel();
292 if (beforePanel
!= null) {
293 beforeBox
.add(beforePanel
.getComponent());
294 beforeVisible
= true;
295 myAdditionalComponents
.add(beforePanel
);
298 final RefreshableOnComponent afterPanel
= handler
.getAfterCheckinConfigurationPanel();
299 if (afterPanel
!= null) {
300 afterBox
.add(afterPanel
.getComponent());
302 myAdditionalComponents
.add(afterPanel
);
306 final String actionName
= getCommitActionName();
307 final String borderTitleName
= actionName
.replace("_", "");
309 beforeBox
.add(Box
.createVerticalGlue());
310 beforeBox
.add(SeparatorFactory
.createSeparator(VcsBundle
.message("border.standard.checkin.options.group", borderTitleName
), null), 0);
311 optionsBox
.add(beforeBox
);
315 afterBox
.add(Box
.createVerticalGlue());
316 afterBox
.add(SeparatorFactory
.createSeparator(VcsBundle
.message("border.standard.after.checkin.options.group", borderTitleName
), null), 0);
317 optionsBox
.add(afterBox
);
320 if (hasVcsOptions
|| beforeVisible
|| afterVisible
) {
321 optionsBox
.add(Box
.createVerticalGlue());
322 myAdditionalOptionsPanel
.add(optionsBox
, BorderLayout
.NORTH
);
325 setOKButtonText(actionName
);
327 if (myShowVcsCommit
) {
328 setTitle(myActionName
);
331 setTitle(trimEllipsis(myExecutors
.get(0).getActionText()));
336 if (myExecutors
!= null) {
337 myExecutorActions
= new Action
[myExecutors
.size()];
339 for (int i
= 0; i
< myExecutors
.size(); i
++) {
340 final CommitExecutor commitExecutor
= myExecutors
.get(i
);
341 myExecutorActions
[i
] = new CommitExecutorAction(commitExecutor
, i
== 0 && !myShowVcsCommit
);
344 myExecutorActions
= null;
347 myWarningLabel
= new JLabel();
348 myWarningLabel
.setUI(new MultiLineLabelUI());
349 myWarningLabel
.setForeground(Color
.red
);
355 updateVcsOptionsVisibility();
357 updateOnListSelection();
358 myCommitMessageArea
.requestFocusInMessage();
360 for (EditChangelistSupport support
: Extensions
.getExtensions(EditChangelistSupport
.EP_NAME
, project
)) {
361 support
.installSearch(myCommitMessageArea
.getTextField(), myCommitMessageArea
.getTextField());
366 private void updateOnListSelection() {
368 updateVcsOptionsVisibility();
369 for (CheckinChangeListSpecificComponent component
: myCheckinChangeListSpecificComponents
.values()) {
370 component
.onChangeListSelected((LocalChangeList
) myBrowser
.getSelectedChangeList());
374 private void updateWarning() {
375 // check for null since can be called from constructor before field initialization
376 if (myWarningLabel
!= null) {
377 myWarningLabel
.setVisible(false);
378 final VcsException updateException
= ((ChangeListManagerImpl
)ChangeListManager
.getInstance(myProject
)).getUpdateException();
379 if (updateException
!= null) {
380 final String
[] messages
= updateException
.getMessages();
381 if (messages
!= null || messages
.length
> 0) {
382 final String message
= messages
[0];
383 myWarningLabel
.setText("Warning: not all local changes may be shown due to an error: " + message
);
384 myWarningLabel
.setVisible(true);
390 private void updateVcsOptionsVisibility() {
391 final List
<AbstractVcs
> affectedVcses
= getAffectedVcses(myBrowser
.getSelectedChangeList().getChanges());
392 for(Map
.Entry
<AbstractVcs
, JPanel
> entry
: myPerVcsOptionsPanels
.entrySet()) {
393 entry
.getValue().setVisible(affectedVcses
.contains(entry
.getKey()));
397 protected Action
[] createActions() {
399 final int executorsSize
= (myExecutors
== null) ?
0 : myExecutors
.size();
401 if (myShowVcsCommit
) {
402 result
= new Action
[2 + executorsSize
];
403 result
[0] = getOKAction();
404 if (myExecutors
!= null) {
405 System
.arraycopy(myExecutorActions
, 0, result
, 1, myExecutorActions
.length
);
409 result
= new Action
[1 + executorsSize
];
410 if (myExecutors
!= null) {
411 System
.arraycopy(myExecutorActions
, 0, result
, 0, myExecutorActions
.length
);
414 result
[result
.length
- 1] = getCancelAction();
418 private void execute(final CommitExecutor commitExecutor
) {
419 if (!saveDialogState()) return;
421 final CommitSession session
= commitExecutor
.createCommitSession();
423 if (SessionDialog
.createConfigurationUI(session
, getIncludedChanges(), getCommitMessage())!= null) {
424 DialogWrapper sessionDialog
= new SessionDialog(commitExecutor
.getActionText(),
427 getIncludedChanges(),
429 sessionDialog
.show();
430 isOK
= sessionDialog
.isOK();
433 final DefaultListCleaner defaultListCleaner
= new DefaultListCleaner();
434 runBeforeCommitHandlers(new Runnable() {
437 final boolean completed
= ProgressManager
.getInstance().runProcessWithProgressSynchronously(new Runnable() {
439 session
.execute(getIncludedChanges(), getCommitMessage());
441 }, commitExecutor
.getActionText(), true, getProject());
444 for (CheckinHandler handler
: myHandlers
) {
445 handler
.checkinSuccessful();
448 defaultListCleaner
.clean();
452 session
.executionCanceled();
455 catch (Throwable e
) {
456 Messages
.showErrorDialog(VcsBundle
.message("error.executing.commit", commitExecutor
.getActionText(), e
.getLocalizedMessage()),
457 commitExecutor
.getActionText());
459 for (CheckinHandler handler
: myHandlers
) {
460 handler
.checkinFailed(Arrays
.asList(new VcsException(e
)));
469 session
.executionCanceled();
474 private String
getInitialMessageFromVcs() {
475 final List
<Change
> list
= getIncludedChanges();
476 final Ref
<String
> result
= new Ref
<String
>();
477 ChangesUtil
.processChangesByVcs(myProject
, list
, new ChangesUtil
.PerVcsProcessor
<Change
>() {
478 public void process(final AbstractVcs vcs
, final List
<Change
> items
) {
479 if (result
.isNull()) {
480 CheckinEnvironment checkinEnvironment
= vcs
.getCheckinEnvironment();
481 if (checkinEnvironment
!= null) {
482 final Collection
<FilePath
> paths
= ChangesUtil
.getPaths(items
);
483 String defaultMessage
= checkinEnvironment
.getDefaultMessageFor(paths
.toArray(new FilePath
[paths
.size()]));
484 if (defaultMessage
!= null) {
485 result
.set(defaultMessage
);
494 private void saveCommentIntoChangeList() {
495 if (myLastSelectedListName
!= null) {
496 final String actualCommentText
= myCommitMessageArea
.getComment();
497 final String saved
= myListComments
.get(myLastSelectedListName
);
498 if (! Comparing
.equal(saved
, actualCommentText
)) {
499 myListComments
.put(myLastSelectedListName
, actualCommentText
);
504 private boolean isDefaultList(final LocalChangeList list
) {
505 return VcsBundle
.message("changes.default.changlist.name").equals(list
.getName());
508 private void updateComment() {
509 final LocalChangeList list
= (LocalChangeList
) myBrowser
.getSelectedChangeList();
510 if (list
== null || (list
.getName().equals(myLastSelectedListName
))) {
512 } else if (myLastSelectedListName
!= null) {
513 saveCommentIntoChangeList();
515 myLastSelectedListName
= list
.getName();
517 String listComment
= list
.getComment();
518 if (StringUtil
.isEmptyOrSpaces(listComment
)) {
519 final String listTitle
= list
.getName();
520 if (! isDefaultList(list
)) {
521 listComment
= listTitle
;
524 // use last know comment; it is already stored in list
525 listComment
= myLastKnownComment
;
529 myCommitMessageArea
.setText(listComment
);
534 public void dispose() {
537 Disposer
.dispose(myCommitMessageArea
);
538 Disposer
.dispose(myOKButtonUpdateAlarm
);
539 myUpdateButtonsRunnable
.cancel();
541 PropertiesComponent
.getInstance().setValue(SPLITTER_PROPORTION_OPTION
, String
.valueOf(mySplitter
.getProportion()));
544 public String
getCommitActionName() {
546 for (AbstractVcs vcs
: getAffectedVcses()) {
547 final CheckinEnvironment checkinEnvironment
= vcs
.getCheckinEnvironment();
548 if (name
== null && checkinEnvironment
!= null) {
549 name
= checkinEnvironment
.getCheckinOperationName();
552 name
= VcsBundle
.message("commit.dialog.default.commit.operation.name");
555 return name
!= null ? name
: VcsBundle
.message("commit.dialog.default.commit.operation.name");
558 private boolean checkComment() {
559 if (VcsConfiguration
.getInstance(myProject
).FORCE_NON_EMPTY_COMMENT
&& (getCommitMessage().length() == 0)) {
560 int requestForCheckin
= Messages
.showYesNoDialog(VcsBundle
.message("confirmation.text.check.in.with.empty.comment"),
561 VcsBundle
.message("confirmation.title.check.in.with.empty.comment"),
562 Messages
.getWarningIcon());
563 return requestForCheckin
== OK_EXIT_CODE
;
570 private void stopUpdate() {
572 myUpdateButtonsRunnable
.cancel();
575 private void restartUpdate() {
577 myUpdateButtonsRunnable
.restart(this);
580 private void runBeforeCommitHandlers(final Runnable okAction
, final CommitExecutor executor
) {
581 Runnable proceedRunnable
= new Runnable() {
583 FileDocumentManager
.getInstance().saveAllDocuments();
585 for (CheckinHandler handler
: myHandlers
) {
586 final CheckinHandler
.ReturnResult result
= handler
.beforeCheckin(executor
);
587 if (result
== CheckinHandler
.ReturnResult
.COMMIT
) continue;
588 if (result
== CheckinHandler
.ReturnResult
.CANCEL
) {
593 if (result
== CheckinHandler
.ReturnResult
.CLOSE_WINDOW
) {
594 final ChangeList changeList
= myBrowser
.getSelectedChangeList();
595 CommitHelper
.moveToFailedList(changeList
,
597 getIncludedChanges(),
598 VcsBundle
.message("commit.dialog.rejected.commit.template", changeList
.getName()),
610 for(CheckinHandler handler
: myHandlers
) {
611 if (handler
instanceof CheckinMetaHandler
) {
612 ((CheckinMetaHandler
) handler
).runCheckinHandlers(proceedRunnable
);
616 proceedRunnable
.run();
619 protected void doOKAction() {
620 if (!saveDialogState()) return;
622 final DefaultListCleaner defaultListCleaner
= new DefaultListCleaner();
624 ensureDataIsActual(new Runnable() {
627 runBeforeCommitHandlers(new Runnable() {
629 CommitChangeListDialog
.super.doOKAction();
634 defaultListCleaner
.clean();
636 catch (InputException ex
) {
643 private boolean saveDialogState() {
644 if (!checkComment()) {
648 saveCommentIntoChangeList();
649 VcsConfiguration
.getInstance(myProject
).saveCommitMessage(getCommitMessage());
653 catch(InputException ex
) {
660 private class DefaultListCleaner
{
661 private final boolean myToClean
;
663 private DefaultListCleaner() {
664 final int selectedSize
= getIncludedChanges().size();
665 final ChangeList selectedList
= myBrowser
.getSelectedChangeList();
666 final int totalSize
= selectedList
.getChanges().size();
667 myToClean
= (totalSize
== selectedSize
) && (isDefaultList((LocalChangeList
) selectedList
));
672 final ChangeListManager clManager
= ChangeListManager
.getInstance(myProject
);
673 clManager
.editComment(myLastSelectedListName
, "");
678 private void saveComments(final boolean isOk
) {
679 final ChangeListManager clManager
= ChangeListManager
.getInstance(myProject
);
681 final int selectedSize
= getIncludedChanges().size();
682 final ChangeList selectedList
= myBrowser
.getSelectedChangeList();
683 final int totalSize
= selectedList
.getChanges().size();
684 if (totalSize
> selectedSize
) {
685 myListComments
.remove(myLastSelectedListName
);
688 for (Map
.Entry
<String
, String
> entry
: myListComments
.entrySet()) {
689 final String name
= entry
.getKey();
690 final String value
= entry
.getValue();
691 clManager
.editComment(name
, value
);
696 public void doCancelAction() {
697 for (CheckinChangeListSpecificComponent component
: myCheckinChangeListSpecificComponents
.values()) {
698 component
.saveState();
700 saveCommentIntoChangeList();
702 //VcsConfiguration.getInstance(myProject).saveCommitMessage(getCommitMessage());
703 super.doCancelAction();
706 private Map
<String
, Object
> getAdditionalDataForSubmit() {
707 final Map
<String
, Object
> result
= new HashMap
<String
, Object
>();
708 for (Map
.Entry
<String
, CheckinChangeListSpecificComponent
> entry
: myCheckinChangeListSpecificComponents
.entrySet()) {
709 final Object data
= entry
.getValue().getDataForCommit();
711 result
.put(entry
.getKey(), data
);
717 private void doCommit() {
718 final CommitHelper helper
= new CommitHelper(
720 myBrowser
.getSelectedChangeList(),
721 getIncludedChanges(),
725 myAllOfDefaultChangeListChangesIncluded
, false, getAdditionalDataForSubmit());
728 helper
.doAlienCommit(myVcs
);
735 protected JComponent
createCenterPanel() {
736 JPanel rootPane
= new JPanel(new BorderLayout());
738 mySplitter
= new Splitter(true);
739 mySplitter
.setHonorComponentsMinimumSize(true);
740 mySplitter
.setFirstComponent(myBrowser
);
741 mySplitter
.setSecondComponent(myCommitMessageArea
);
742 mySplitter
.setProportion(calcSplitterProportion());
743 mySplitter
.setDividerWidth(3);
744 rootPane
.add(mySplitter
, BorderLayout
.CENTER
);
746 JComponent browserHeader
= myBrowser
.getHeaderPanel();
747 myBrowser
.remove(browserHeader
);
748 rootPane
.add(browserHeader
, BorderLayout
.NORTH
);
750 JPanel infoPanel
= new JPanel(new BorderLayout());
751 myLegend
= new CommitLegendPanel();
752 infoPanel
.add(myLegend
.getComponent(), BorderLayout
.NORTH
);
753 infoPanel
.add(myAdditionalOptionsPanel
, BorderLayout
.CENTER
);
754 rootPane
.add(infoPanel
, BorderLayout
.EAST
);
755 infoPanel
.setBorder(IdeBorderFactory
.createEmptyBorder(0, 10, 0, 0));
757 rootPane
.add(myWarningLabel
, BorderLayout
.SOUTH
);
762 private static float calcSplitterProportion() {
764 final String s
= PropertiesComponent
.getInstance().getValue(SPLITTER_PROPORTION_OPTION
);
765 return s
!= null ? Float
.valueOf(s
).floatValue() : 0.5f
;
767 catch (NumberFormatException e
) {
772 public List
<AbstractVcs
> getAffectedVcses() {
773 if (! myShowVcsCommit
) {
774 return Collections
.emptyList();
776 return myBrowserExtender
.getAffectedVcses();
779 private List
<AbstractVcs
> getAffectedVcses(final Collection
<Change
> changes
) {
780 Set
<AbstractVcs
> result
= new HashSet
<AbstractVcs
>();
781 for (Change change
: changes
) {
782 final AbstractVcs vcs
= ChangesUtil
.getVcsForChange(change
, myProject
);
787 return new ArrayList
<AbstractVcs
>(result
);
790 public Collection
<VirtualFile
> getRoots() {
791 Set
<VirtualFile
> result
= new HashSet
<VirtualFile
>();
792 for (Change change
: myBrowser
.getCurrentDisplayedChanges()) {
793 final FilePath filePath
= ChangesUtil
.getFilePath(change
);
794 VirtualFile root
= ProjectLevelVcsManager
.getInstance(myProject
).getVcsRootFor(filePath
);
802 public JComponent
getComponent() {
806 public boolean hasDiffs() {
807 return !getIncludedChanges().isEmpty();
810 public Collection
<VirtualFile
> getVirtualFiles() {
811 List
<VirtualFile
> result
= new ArrayList
<VirtualFile
>();
812 for (Change change
: getIncludedChanges()) {
813 final FilePath path
= ChangesUtil
.getFilePath(change
);
814 final VirtualFile vFile
= path
.getVirtualFile();
823 public Collection
<Change
> getSelectedChanges() {
824 return new ArrayList
<Change
>(getIncludedChanges());
827 public Collection
<File
> getFiles() {
828 List
<File
> result
= new ArrayList
<File
>();
829 for (Change change
: getIncludedChanges()) {
830 final FilePath path
= ChangesUtil
.getFilePath(change
);
831 final File file
= path
.getIOFile();
838 public Project
getProject() {
842 public void setCommitMessage(final String currentDescription
) {
843 setCommitMessageText(currentDescription
);
844 myCommitMessageArea
.requestFocusInMessage();
847 public Object
getContextInfo(Object object
) {
852 public void setWarning(String s
) {
856 private void setCommitMessageText(final String currentDescription
) {
857 myLastKnownComment
= currentDescription
;
858 myCommitMessageArea
.setText(currentDescription
);
861 public String
getCommitMessage() {
862 return myCommitMessageArea
.getComment();
865 public void refresh() {
866 ChangeListManager
.getInstance(myProject
).invokeAfterUpdate(new Runnable() {
868 myBrowser
.rebuildList();
869 for (RefreshableOnComponent component
: myAdditionalComponents
) {
873 }, InvokeAfterUpdateMode
.SILENT
, "commit dialog", ModalityState
.current()); // title not shown for silently
876 public void saveState() {
877 for (RefreshableOnComponent component
: myAdditionalComponents
) {
878 component
.saveState();
882 public void restoreState() {
883 for (RefreshableOnComponent component
: myAdditionalComponents
) {
884 component
.restoreState();
888 private void updateButtons() {
889 if (myDisposed
) return;
890 setOKActionEnabled(hasDiffs());
891 if (myExecutorActions
!= null) {
892 for (Action executorAction
: myExecutorActions
) {
893 executorAction
.setEnabled(hasDiffs());
896 myOKButtonUpdateAlarm
.cancelAllRequests();
897 myOKButtonUpdateAlarm
.addRequest(myUpdateButtonsRunnable
, 300, ModalityState
.stateForComponent(myBrowser
));
900 private void updateLegend() {
901 if (myDisposed
) return;
902 myLegend
.update(myBrowser
.getCurrentDisplayedChanges(), myBrowserExtender
.getCurrentIncludedChanges());
906 private List
<Change
> getIncludedChanges() {
907 return myBrowserExtender
.getCurrentIncludedChanges();
911 protected String
getDimensionServiceKey() {
912 return "CommitChangelistDialog";
915 public JComponent
getPreferredFocusedComponent() {
916 return myCommitMessageArea
.getTextField();
919 public void calcData(DataKey key
, DataSink sink
) {
920 if (key
== CheckinProjectPanel
.PANEL_KEY
) {
921 sink
.put(CheckinProjectPanel
.PANEL_KEY
, this);
924 myBrowser
.calcData(key
, sink
);
928 static String
trimEllipsis(final String title
) {
929 if (title
.endsWith("...")) {
930 return title
.substring(0, title
.length() - 3);
937 private void ensureDataIsActual(final Runnable runnable
) {
938 ChangeListManager
.getInstance(myProject
).invokeAfterUpdate(runnable
, InvokeAfterUpdateMode
.SYNCHRONOUS_CANCELLABLE
,
939 "Refreshing changelists...", ModalityState
.current());
942 private class CommitExecutorAction
extends AbstractAction
{
943 private final CommitExecutor myCommitExecutor
;
945 public CommitExecutorAction(final CommitExecutor commitExecutor
, final boolean isDefault
) {
946 super(commitExecutor
.getActionText());
947 myCommitExecutor
= commitExecutor
;
949 putValue(DEFAULT_ACTION
, Boolean
.TRUE
);
953 public void actionPerformed(ActionEvent e
) {
954 ensureDataIsActual(new Runnable() {
956 execute(myCommitExecutor
);
962 private static class DiffCommitMessageEditor
extends JPanel
implements Disposable
{
963 private CommitChangeListDialog myCommitDialog
;
964 private final JTextArea myArea
= new JTextArea();
966 public DiffCommitMessageEditor(final CommitChangeListDialog dialog
) {
967 super(new BorderLayout());
968 myArea
.setText(dialog
.getCommitMessage());
969 myArea
.setLineWrap(true);
970 myArea
.setWrapStyleWord(true);
971 JScrollPane scrollPane
= new JScrollPane(myArea
);
972 setBorder(IdeBorderFactory
.createTitledBorder(VcsBundle
.message("diff.commit.message.title")));
973 add(scrollPane
, BorderLayout
.CENTER
);
974 myCommitDialog
= dialog
;
977 public void dispose() {
978 if (myCommitDialog
!= null) {
979 myCommitDialog
.setCommitMessageText(myArea
.getText());
980 myCommitDialog
= null;
984 public Dimension
getPreferredSize() {
985 // we don't want to be squeezed to one line
986 return new Dimension(400, 120);