JAL-3878 Add annotation operation and worker to the services.
[jalview.git] / src / jalview / ws2 / gui / AlignmentProgressUpdater.java
1 package jalview.ws2.gui;
2
3 import static java.lang.String.format;
4
5 import java.util.ArrayList;
6 import java.util.List;
7 import java.util.function.Consumer;
8
9 import jalview.ws2.operations.WebServiceWorkerListener;
10 import jalview.datamodel.Alignment;
11 import jalview.datamodel.AlignmentI;
12 import jalview.datamodel.AlignmentOrder;
13 import jalview.datamodel.HiddenColumns;
14 import jalview.gui.AlignFrame;
15 import jalview.gui.Desktop;
16 import jalview.gui.JvOptionPane;
17 import jalview.gui.WebserviceInfo;
18 import jalview.util.MessageManager;
19 import jalview.ws2.operations.AlignmentWorker.AlignmentResult;
20 import jalview.ws2.WSJob;
21 import jalview.ws2.operations.WebServiceWorkerI;
22
23 public class AlignmentProgressUpdater
24     implements WebServiceWorkerListener, Consumer<AlignmentResult>
25 {
26   WebServiceWorkerI worker;
27
28   WebserviceInfo wsInfo;
29
30   AlignFrame frame;
31
32   private final WebServiceInfoUpdater wsInfoUpdater;
33
34   String outputHeader;
35
36   AlignmentProgressUpdater(WebServiceWorkerI worker,
37       WebserviceInfo wsInfo, AlignFrame frame, String header)
38   {
39     this.worker = worker;
40     this.wsInfo = wsInfo;
41     this.outputHeader = header;
42     this.wsInfoUpdater = new WebServiceInfoUpdater(worker, wsInfo);
43     wsInfoUpdater.setOutputHeader(header);
44   }
45
46   @Override
47   public void workerStarted(WebServiceWorkerI source)
48   {
49     wsInfo.setVisible(true);
50   }
51
52   @Override
53   public void workerNotStarted(WebServiceWorkerI source)
54   {
55     wsInfo.setVisible(false);
56     // TODO show notification dialog.
57     JvOptionPane.showMessageDialog(frame,
58         MessageManager.getString("info.invalid_msa_input_mininfo"),
59         MessageManager.getString("info.invalid_msa_notenough"),
60         JvOptionPane.INFORMATION_MESSAGE);
61   }
62
63   @Override
64   public void jobCreated(WebServiceWorkerI source, WSJob job)
65   {
66     int tabIndex = wsInfo.addJobPane();
67     wsInfo.setProgressName(format("region %d", job.getJobNum()), tabIndex);
68     wsInfo.setProgressText(tabIndex, outputHeader);
69     job.addPropertyChangeListener(wsInfoUpdater);
70   }
71
72   @Override
73   public void pollException(WebServiceWorkerI source, WSJob job, Exception e)
74   {
75     wsInfo.appendProgressText(job.getJobNum(),
76         MessageManager.formatMessage("info.server_exception",
77             source.getOperation().getName(), e.getMessage()));
78   }
79
80   @Override
81   public void workerCompleting(WebServiceWorkerI source)
82   {
83     wsInfo.setProgressBar(
84         MessageManager.getString("status.collecting_job_results"),
85         worker.getUID());
86   }
87
88   @Override
89   public void workerCompleted(WebServiceWorkerI source)
90   {
91     wsInfo.removeProgressBar(worker.getUID());
92   }
93
94   @Override
95   public void accept(AlignmentResult out)
96   {
97     if (out != null)
98     {
99       wsInfo.showResultsNewFrame.addActionListener(evt -> displayNewFrame(
100           new Alignment(out.getAlignment()), out.getAlignmentOrders(),
101           out.getHiddenColumns()));
102       wsInfo.setResultsReady();
103     }
104     else
105     {
106       wsInfo.setFinishedNoResults();
107     }
108   }
109
110   private void displayNewFrame(AlignmentI aln,
111       List<AlignmentOrder> alorders, HiddenColumns hidden)
112   {
113     AlignFrame frame = new AlignFrame(aln, hidden,
114         AlignFrame.DEFAULT_WIDTH, AlignFrame.DEFAULT_HEIGHT);
115     // TODO store feature renderer settings in worker object
116     // frame.getFeatureRenderer().transferSettings(featureSettings);
117     var regions = sortOrders(alorders);
118     if (alorders.size() == 1)
119     {
120       frame.addSortByOrderMenuItem(format("%s Ordering",
121           worker.getOperation().getName()), alorders.get(0));
122     }
123     else
124     {
125       for (int i = 0; i < alorders.size(); i++)
126       {
127         final int j = i;
128         Iterable<String> iter = () -> regions.get(j).stream()
129             .map(it -> Integer.toString(it)).iterator();
130         var orderName = format("%s Region %s Ordering",
131             worker.getOperation().getName(), String.join(",", iter));
132         frame.addSortByOrderMenuItem(orderName, alorders.get(i));
133       }
134     }
135
136     /* TODO
137      * If alignment was requested from one half of a SplitFrame, show in a
138      * SplitFrame with the other pane similarly aligned.
139      */
140
141     Desktop.addInternalFrame(frame, frame.getTitle(), AlignFrame.DEFAULT_WIDTH,
142         AlignFrame.DEFAULT_HEIGHT);
143   }
144
145   private List<List<Integer>> sortOrders(List<?> alorders)
146   {
147     List<List<Integer>> regions = new ArrayList<>();
148     for (int i = 0; i < alorders.size(); i++)
149     {
150       List<Integer> regs = new ArrayList<>();
151       regs.add(i);
152       int j = i + 1;
153       while (j < alorders.size())
154       {
155         if (alorders.get(i).equals(alorders.get(j)))
156         {
157           alorders.remove(j);
158           regs.add(j);
159         }
160         else
161         {
162           j++;
163         }
164       }
165       regions.add(regs);
166     }
167     return regions;
168   }
169
170 }