1 /************************************************************** 2 * 3 * Licensed to the Apache Software Foundation (ASF) under one 4 * or more contributor license agreements. See the NOTICE file 5 * distributed with this work for additional information 6 * regarding copyright ownership. The ASF licenses this file 7 * to you under the Apache License, Version 2.0 (the 8 * "License"); you may not use this file except in compliance 9 * with the License. You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, 14 * software distributed under the License is distributed on an 15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 * KIND, either express or implied. See the License for the 17 * specific language governing permissions and limitations 18 * under the License. 19 * 20 *************************************************************/ 21 22 23 24 package com.sun.star.wiki; 25 26 import com.sun.star.uno.Any; 27 import com.sun.star.awt.XDialog; 28 import com.sun.star.awt.XCallback; 29 import com.sun.star.awt.XRequestCallback; 30 import com.sun.star.lang.XMultiComponentFactory; 31 import com.sun.star.uno.UnoRuntime; 32 import com.sun.star.uno.XComponentContext; 33 import java.util.concurrent.Callable; 34 35 public class MainThreadDialogExecutor implements XCallback 36 { 37 private Callable<Boolean> m_aTask; 38 private XDialog m_xDialog; 39 private boolean m_bResult = false; 40 private boolean m_bCalled = false; 41 private boolean m_bClose = false; 42 43 /** Runs aTask on the main thread. Dialogs and message boxes must also be created there: 44 on macOS a window created on another thread gets no native window and its modal execute never returns. */ Run( XComponentContext xContext, Callable<Boolean> aTask )45 static public boolean Run( XComponentContext xContext, Callable<Boolean> aTask ) 46 { 47 MainThreadDialogExecutor aExecutor = new MainThreadDialogExecutor( aTask ); 48 return GetCallback( xContext, aExecutor ); 49 } 50 Execute( XComponentContext xContext, XDialog xDialog )51 static public boolean Execute( XComponentContext xContext, XDialog xDialog ) 52 { 53 MainThreadDialogExecutor aExecutor = new MainThreadDialogExecutor( xDialog ); 54 return GetCallback( xContext, aExecutor ); 55 } 56 Close( XComponentContext xContext, XDialog xDialog )57 static public boolean Close( XComponentContext xContext, XDialog xDialog ) 58 { 59 MainThreadDialogExecutor aExecutor = new MainThreadDialogExecutor( xDialog, true ); 60 return GetCallback( xContext, aExecutor ); 61 } 62 GetCallback( XComponentContext xContext, MainThreadDialogExecutor aExecutor )63 static private boolean GetCallback( XComponentContext xContext, MainThreadDialogExecutor aExecutor ) 64 { 65 try 66 { 67 if ( aExecutor != null ) 68 { 69 String aThreadName = null; 70 Thread aCurThread = Thread.currentThread(); 71 if ( aCurThread != null ) 72 aThreadName = aCurThread.getName(); 73 74 if ( aThreadName != null && aThreadName.equals( "com.sun.star.thread.WikiEditorSendingThread" ) ) 75 { 76 // the main thread should be accessed asynchronously 77 XMultiComponentFactory xFactory = xContext.getServiceManager(); 78 if ( xFactory == null ) 79 throw new com.sun.star.uno.RuntimeException(); 80 81 XRequestCallback xRequest = UnoRuntime.queryInterface( 82 XRequestCallback.class, 83 xFactory.createInstanceWithContext( "com.sun.star.awt.AsyncCallback", xContext ) ); 84 if ( xRequest != null ) 85 { 86 xRequest.addCallback( aExecutor, Any.VOID ); 87 aExecutor.WaitForCall(); 88 } 89 } 90 else 91 { 92 // handle it as a main thread 93 aExecutor.notify( Any.VOID ); 94 } 95 } 96 } 97 catch( Exception e ) 98 { 99 e.printStackTrace(); 100 } 101 102 return aExecutor.GetResult(); 103 } 104 MainThreadDialogExecutor( Callable<Boolean> aTask )105 private MainThreadDialogExecutor( Callable<Boolean> aTask ) 106 { 107 m_aTask = aTask; 108 } 109 MainThreadDialogExecutor( XDialog xDialog )110 private MainThreadDialogExecutor( XDialog xDialog ) 111 { 112 m_xDialog = xDialog; 113 } 114 MainThreadDialogExecutor( XDialog xDialog, boolean bClose )115 private MainThreadDialogExecutor( XDialog xDialog, boolean bClose ) 116 { 117 m_xDialog = xDialog; 118 m_bClose = true; 119 m_bCalled = true; // no waiting, asynchronous closing 120 } 121 WaitForCall()122 private void WaitForCall() 123 { 124 boolean bInterrupted = false; 125 synchronized( this ) 126 { 127 while( !m_bCalled ) 128 { 129 try 130 { 131 wait(); 132 } 133 catch( InterruptedException e ) 134 { 135 bInterrupted = true; 136 } 137 } 138 } 139 if ( bInterrupted ) 140 Thread.currentThread().interrupt(); 141 } 142 GetResult()143 private boolean GetResult() 144 { 145 return m_bResult; 146 } 147 notify( Object aData )148 public void notify( Object aData ) 149 { 150 try 151 { 152 CallInMainThread(); 153 } 154 finally 155 { 156 synchronized( this ) 157 { 158 m_bCalled = true; 159 notifyAll(); 160 } 161 } 162 } 163 CallInMainThread()164 private void CallInMainThread() 165 { 166 if ( m_aTask != null ) 167 { 168 try 169 { 170 m_bResult = m_aTask.call().booleanValue(); 171 } 172 catch( Exception e ) 173 { 174 e.printStackTrace(); 175 } 176 } 177 else if ( m_xDialog != null ) 178 { 179 if ( !m_bClose ) 180 m_bResult = ( m_xDialog.execute() == 1 ); 181 else 182 { 183 try 184 { 185 m_xDialog.endExecute(); 186 } 187 catch( Exception e ) 188 { 189 e.printStackTrace(); 190 } 191 m_bResult = true; 192 } 193 } 194 } 195 } 196