Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 :
21 : #include "atkwrapper.hxx"
22 :
23 : #include <com/sun/star/accessibility/XAccessibleTable.hpp>
24 :
25 : #ifdef ENABLE_TRACING
26 : #include <stdio.h>
27 : #endif
28 :
29 : using namespace ::com::sun::star;
30 :
31 : static inline AtkObject *
32 0 : atk_object_wrapper_conditional_ref( const uno::Reference< accessibility::XAccessible >& rxAccessible )
33 : {
34 : #ifdef ENABLE_TRACING
35 : fprintf( stderr, ": %p\n", rxAccessible.get() );
36 : #endif
37 :
38 0 : if( rxAccessible.is() )
39 0 : return atk_object_wrapper_ref( rxAccessible );
40 :
41 0 : return NULL;
42 : }
43 :
44 : /*****************************************************************************/
45 :
46 : // FIXME
47 : static G_CONST_RETURN gchar *
48 0 : getAsConst( rtl::OUString rString )
49 : {
50 : static const int nMax = 10;
51 0 : static rtl::OString aUgly[nMax];
52 : static int nIdx = 0;
53 0 : nIdx = (nIdx + 1) % nMax;
54 0 : aUgly[nIdx] = rtl::OUStringToOString( rString, RTL_TEXTENCODING_UTF8 );
55 0 : return aUgly[ nIdx ].getStr();
56 : }
57 :
58 : /*****************************************************************************/
59 :
60 : static accessibility::XAccessibleTable*
61 0 : getTable( AtkTable *pTable ) throw (uno::RuntimeException)
62 : {
63 0 : AtkObjectWrapper *pWrap = ATK_OBJECT_WRAPPER( pTable );
64 0 : if( pWrap )
65 : {
66 0 : if( !pWrap->mpTable && pWrap->mpContext )
67 : {
68 0 : uno::Any any = pWrap->mpContext->queryInterface( accessibility::XAccessibleTable::static_type(NULL) );
69 0 : pWrap->mpTable = reinterpret_cast< accessibility::XAccessibleTable * > (any.pReserved);
70 0 : pWrap->mpTable->acquire();
71 : }
72 :
73 0 : return pWrap->mpTable;
74 : }
75 :
76 0 : return NULL;
77 : }
78 :
79 : /*****************************************************************************/
80 :
81 : extern "C" {
82 :
83 : static AtkObject*
84 0 : table_wrapper_ref_at (AtkTable *table,
85 : gint row,
86 : gint column)
87 : {
88 : try {
89 0 : accessibility::XAccessibleTable* pTable = getTable( table );
90 :
91 : #ifdef ENABLE_TRACING
92 : if( pTable )
93 : fprintf(stderr, "getAccessibleCellAt( %u, %u ) returns", row, column );
94 :
95 : if( column >= 255 )
96 : fprintf(stderr, "getAccessibleCellAt( %u, %u ) returns", row, column );
97 :
98 : #endif
99 :
100 0 : if( pTable )
101 0 : return atk_object_wrapper_conditional_ref( pTable->getAccessibleCellAt( row, column ) );
102 : }
103 :
104 0 : catch(const uno::Exception& e) {
105 0 : g_warning( "Exception in getAccessibleCellAt()" );
106 : }
107 :
108 0 : return NULL;
109 : }
110 :
111 : /*****************************************************************************/
112 :
113 : static gint
114 0 : table_wrapper_get_index_at (AtkTable *table,
115 : gint row,
116 : gint column)
117 : {
118 : try {
119 0 : accessibility::XAccessibleTable* pTable = getTable( table );
120 :
121 : #ifdef ENABLE_TRACING
122 : if( pTable )
123 : fprintf(stderr, "getAccessibleIndex( %u, %u ) returns %u\n",
124 : row, column, pTable->getAccessibleIndex( row, column ) );
125 : #endif
126 :
127 0 : if( pTable )
128 0 : return pTable->getAccessibleIndex( row, column );
129 : }
130 0 : catch(const uno::Exception& e) {
131 0 : g_warning( "Exception in getAccessibleIndex()" );
132 : }
133 :
134 0 : return -1;
135 : }
136 :
137 : /*****************************************************************************/
138 :
139 : static gint
140 0 : table_wrapper_get_column_at_index (AtkTable *table,
141 : gint nIndex)
142 : {
143 : try {
144 0 : accessibility::XAccessibleTable* pTable = getTable( table );
145 :
146 : #ifdef ENABLE_TRACING
147 : if( pTable )
148 : fprintf(stderr, "getAccessibleColumn( %u ) returns %u\n",
149 : nIndex, pTable->getAccessibleColumn( nIndex ) );
150 : #endif
151 :
152 0 : if( pTable )
153 0 : return pTable->getAccessibleColumn( nIndex );
154 : }
155 0 : catch(const uno::Exception& e) {
156 0 : g_warning( "Exception in getAccessibleColumn()" );
157 : }
158 :
159 0 : return -1;
160 : }
161 :
162 : /*****************************************************************************/
163 :
164 : static gint
165 0 : table_wrapper_get_row_at_index( AtkTable *table,
166 : gint nIndex )
167 : {
168 : try {
169 0 : accessibility::XAccessibleTable* pTable = getTable( table );
170 :
171 : #ifdef ENABLE_TRACING
172 : if( pTable )
173 : fprintf(stderr, "getAccessibleRow( %u ) returns %u\n",
174 : nIndex, pTable->getAccessibleRow( nIndex ) );
175 : #endif
176 :
177 0 : if( pTable )
178 0 : return pTable->getAccessibleRow( nIndex );
179 : }
180 0 : catch(const uno::Exception& e) {
181 0 : g_warning( "Exception in getAccessibleRow()" );
182 : }
183 :
184 0 : return -1;
185 : }
186 :
187 : /*****************************************************************************/
188 :
189 : static gint
190 0 : table_wrapper_get_n_columns( AtkTable *table )
191 : {
192 : try {
193 0 : accessibility::XAccessibleTable* pTable = getTable( table );
194 :
195 : #ifdef ENABLE_TRACING
196 : if( pTable )
197 : fprintf(stderr, "XAccessibleTable::getAccessibleColumnCount returns %u\n",
198 : pTable->getAccessibleColumnCount() );
199 : #endif
200 :
201 0 : if( pTable )
202 0 : return pTable->getAccessibleColumnCount();
203 : }
204 0 : catch(const uno::Exception& e) {
205 0 : g_warning( "Exception in getAccessibleColumnCount()" );
206 : }
207 :
208 0 : return -1;
209 : }
210 :
211 : /*****************************************************************************/
212 :
213 : static gint
214 0 : table_wrapper_get_n_rows( AtkTable *table )
215 : {
216 : try {
217 0 : accessibility::XAccessibleTable* pTable = getTable( table );
218 :
219 : #ifdef ENABLE_TRACING
220 : if( pTable )
221 : fprintf(stderr, "getAccessibleRowCount() returns %u\n",
222 : pTable->getAccessibleRowCount() );
223 : #endif
224 :
225 0 : if( pTable )
226 0 : return pTable->getAccessibleRowCount();
227 : }
228 0 : catch(const uno::Exception& e) {
229 0 : g_warning( "Exception in getAccessibleRowCount()" );
230 : }
231 :
232 0 : return -1;
233 : }
234 :
235 : /*****************************************************************************/
236 :
237 : static gint
238 0 : table_wrapper_get_column_extent_at( AtkTable *table,
239 : gint row,
240 : gint column )
241 : {
242 : try {
243 0 : accessibility::XAccessibleTable* pTable = getTable( table );
244 :
245 : #ifdef ENABLE_TRACING
246 : if( pTable )
247 : fprintf(stderr, "getAccessibleColumnExtentAt( %u, %u ) returns %u\n",
248 : row, column, pTable->getAccessibleColumnExtentAt( row, column ) );
249 : #endif
250 :
251 0 : if( pTable )
252 0 : return pTable->getAccessibleColumnExtentAt( row, column );
253 : }
254 0 : catch(const uno::Exception& e) {
255 0 : g_warning( "Exception in getAccessibleColumnExtentAt()" );
256 : }
257 :
258 0 : return -1;
259 : }
260 :
261 : /*****************************************************************************/
262 :
263 : static gint
264 0 : table_wrapper_get_row_extent_at( AtkTable *table,
265 : gint row,
266 : gint column )
267 : {
268 : try {
269 0 : accessibility::XAccessibleTable* pTable = getTable( table );
270 :
271 : #ifdef ENABLE_TRACING
272 : if( pTable )
273 : fprintf(stderr, "getAccessibleRowExtentAt( %u, %u ) returns %u\n",
274 : row, column, pTable->getAccessibleRowExtentAt( row, column ) );
275 : #endif
276 :
277 0 : if( pTable )
278 0 : return pTable->getAccessibleRowExtentAt( row, column );
279 : }
280 0 : catch(const uno::Exception& e) {
281 0 : g_warning( "Exception in getAccessibleRowExtentAt()" );
282 : }
283 :
284 0 : return -1;
285 : }
286 :
287 : /*****************************************************************************/
288 :
289 : static AtkObject *
290 0 : table_wrapper_get_caption( AtkTable *table )
291 : {
292 : try {
293 0 : accessibility::XAccessibleTable* pTable = getTable( table );
294 :
295 : #ifdef ENABLE_TRACING
296 : if( pTable )
297 : fprintf(stderr, "getAccessibleCaption() returns" );
298 : #endif
299 :
300 0 : if( pTable )
301 0 : return atk_object_wrapper_conditional_ref( pTable->getAccessibleCaption() );
302 : }
303 :
304 0 : catch(const uno::Exception& e) {
305 0 : g_warning( "Exception in getAccessibleCaption()" );
306 : }
307 :
308 0 : return NULL;
309 : }
310 :
311 : /*****************************************************************************/
312 :
313 : static G_CONST_RETURN gchar *
314 0 : table_wrapper_get_row_description( AtkTable *table,
315 : gint row )
316 : {
317 : try {
318 0 : accessibility::XAccessibleTable* pTable = getTable( table );
319 :
320 : #ifdef ENABLE_TRACING
321 : if( pTable )
322 : fprintf(stderr, "getAccessibleRowDescription( %u ) returns %s\n",
323 : row, getAsConst( pTable->getAccessibleRowDescription( row ) ) );
324 : #endif
325 :
326 0 : if( pTable )
327 0 : return getAsConst( pTable->getAccessibleRowDescription( row ) );
328 : }
329 0 : catch(const uno::Exception& e) {
330 0 : g_warning( "Exception in getAccessibleRowDescription()" );
331 : }
332 :
333 0 : return NULL;
334 : }
335 :
336 : /*****************************************************************************/
337 :
338 : static G_CONST_RETURN gchar *
339 0 : table_wrapper_get_column_description( AtkTable *table,
340 : gint column )
341 : {
342 : try {
343 0 : accessibility::XAccessibleTable* pTable = getTable( table );
344 :
345 : #ifdef ENABLE_TRACING
346 : if( pTable )
347 : fprintf(stderr, "getAccessibleColumnDescription( %u ) returns %s\n",
348 : column, getAsConst( pTable->getAccessibleColumnDescription( column ) ) );
349 : #endif
350 :
351 0 : if( pTable )
352 0 : return getAsConst( pTable->getAccessibleColumnDescription( column ) );
353 : }
354 0 : catch(const uno::Exception& e) {
355 0 : g_warning( "Exception in getAccessibleColumnDescription()" );
356 : }
357 :
358 0 : return NULL;
359 : }
360 :
361 : /*****************************************************************************/
362 :
363 : static AtkObject *
364 0 : table_wrapper_get_row_header( AtkTable *table,
365 : gint row )
366 : {
367 : try {
368 0 : accessibility::XAccessibleTable* pTable = getTable( table );
369 0 : if( pTable )
370 : {
371 0 : uno::Reference< accessibility::XAccessibleTable > xRowHeaders( pTable->getAccessibleRowHeaders() );
372 :
373 : #ifdef ENABLE_TRACING
374 : if( xRowHeaders.is() )
375 : fprintf(stderr, "getAccessibleRowHeader( %u )->getAccessibleCellAt( 0, %u ) returns",
376 : row, row );
377 : else
378 : fprintf(stderr, "getAccessibleRowHeader( %u ) returns %p\n", row, xRowHeaders.get() );
379 : #endif
380 :
381 0 : if( xRowHeaders.is() )
382 0 : return atk_object_wrapper_conditional_ref( xRowHeaders->getAccessibleCellAt( row, 0 ) );
383 : }
384 : }
385 0 : catch(const uno::Exception& e) {
386 0 : g_warning( "Exception in getAccessibleRowHeaders()" );
387 : }
388 :
389 0 : return NULL;
390 : }
391 :
392 : /*****************************************************************************/
393 :
394 : static AtkObject *
395 0 : table_wrapper_get_column_header( AtkTable *table,
396 : gint column )
397 : {
398 : try {
399 0 : accessibility::XAccessibleTable* pTable = getTable( table );
400 :
401 0 : if( pTable )
402 : {
403 0 : uno::Reference< accessibility::XAccessibleTable > xColumnHeaders( pTable->getAccessibleColumnHeaders() );
404 :
405 : #ifdef ENABLE_TRACING
406 : if( xColumnHeaders.is() )
407 : fprintf(stderr, "getAccessibleColumnHeader( %u )->getAccessibleCellAt( 0, %u ) returns",
408 : column, column );
409 : else
410 : fprintf(stderr, "getAccessibleColumnHeader( %u ) returns %p\n", column, xColumnHeaders.get() );
411 : #endif
412 :
413 0 : if( xColumnHeaders.is() )
414 0 : return atk_object_wrapper_conditional_ref( xColumnHeaders->getAccessibleCellAt( 0, column ) );
415 : }
416 : }
417 0 : catch(const uno::Exception& e) {
418 0 : g_warning( "Exception in getAccessibleColumnHeaders()" );
419 : }
420 :
421 0 : return NULL;
422 : }
423 :
424 : /*****************************************************************************/
425 :
426 : static AtkObject *
427 0 : table_wrapper_get_summary( AtkTable *table )
428 : {
429 : try {
430 0 : accessibility::XAccessibleTable* pTable = getTable( table );
431 :
432 : #ifdef ENABLE_TRACING
433 : if( pTable )
434 : fprintf(stderr, "getAccessibleSummary() returns" );
435 : #endif
436 :
437 0 : if( pTable )
438 : {
439 0 : return atk_object_wrapper_conditional_ref( pTable->getAccessibleSummary() );
440 : }
441 : }
442 0 : catch(const uno::Exception& e) {
443 0 : g_warning( "Exception in getAccessibleSummary()" );
444 : }
445 :
446 0 : return NULL;
447 : }
448 :
449 : /*****************************************************************************/
450 :
451 : static gint
452 0 : convertToGIntArray( const uno::Sequence< ::sal_Int32 >& aSequence, gint **pSelected )
453 : {
454 0 : if( aSequence.getLength() )
455 : {
456 0 : *pSelected = g_new( gint, aSequence.getLength() );
457 :
458 0 : for( sal_Int32 i = 0; i < aSequence.getLength(); i++ )
459 0 : (*pSelected) [i] = aSequence[i];
460 : }
461 :
462 0 : return aSequence.getLength();
463 : }
464 :
465 : /*****************************************************************************/
466 :
467 : static gint
468 0 : table_wrapper_get_selected_columns( AtkTable *table,
469 : gint **pSelected )
470 : {
471 0 : *pSelected = NULL;
472 : try {
473 0 : accessibility::XAccessibleTable* pTable = getTable( table );
474 :
475 : #ifdef ENABLE_TRACING
476 : if( pTable )
477 : fprintf(stderr, "getSelectedAccessibleColumns() \n" );
478 : #endif
479 :
480 0 : if( pTable )
481 0 : return convertToGIntArray( pTable->getSelectedAccessibleColumns(), pSelected );
482 : }
483 0 : catch(const uno::Exception& e) {
484 0 : g_warning( "Exception in getSelectedAccessibleColumns()" );
485 : }
486 :
487 0 : return 0;
488 : }
489 :
490 : /*****************************************************************************/
491 :
492 : static gint
493 0 : table_wrapper_get_selected_rows( AtkTable *table,
494 : gint **pSelected )
495 : {
496 0 : *pSelected = NULL;
497 : try {
498 0 : accessibility::XAccessibleTable* pTable = getTable( table );
499 :
500 : #ifdef ENABLE_TRACING
501 : if( pTable )
502 : fprintf(stderr, "getSelectedAccessibleRows() \n" );
503 : #endif
504 :
505 0 : if( pTable )
506 0 : return convertToGIntArray( pTable->getSelectedAccessibleRows(), pSelected );
507 : }
508 0 : catch(const uno::Exception& e) {
509 0 : g_warning( "Exception in getSelectedAccessibleRows()" );
510 : }
511 :
512 0 : return 0;
513 : }
514 :
515 : /*****************************************************************************/
516 :
517 : static gboolean
518 0 : table_wrapper_is_column_selected( AtkTable *table,
519 : gint column )
520 : {
521 : try {
522 0 : accessibility::XAccessibleTable* pTable = getTable( table );
523 :
524 : #ifdef ENABLE_TRACING
525 : if( pTable )
526 : fprintf(stderr, "isAccessibleColumnSelected( %u ) returns %s\n",
527 : column, pTable->isAccessibleColumnSelected( column ) ? "true" : "false" );
528 : #endif
529 :
530 0 : if( pTable )
531 0 : return pTable->isAccessibleColumnSelected( column );
532 : }
533 0 : catch(const uno::Exception& e) {
534 0 : g_warning( "Exception in isAccessibleColumnSelected()" );
535 : }
536 :
537 0 : return 0;
538 : }
539 :
540 : /*****************************************************************************/
541 :
542 : static gboolean
543 0 : table_wrapper_is_row_selected( AtkTable *table,
544 : gint row )
545 : {
546 : try {
547 0 : accessibility::XAccessibleTable* pTable = getTable( table );
548 :
549 : #ifdef ENABLE_TRACING
550 : if( pTable )
551 : fprintf(stderr, "isAccessibleRowSelected( %u ) returns %s\n",
552 : row, pTable->isAccessibleRowSelected( row ) ? "true" : "false" );
553 : #endif
554 :
555 0 : if( pTable )
556 0 : return pTable->isAccessibleRowSelected( row );
557 : }
558 0 : catch(const uno::Exception& e) {
559 0 : g_warning( "Exception in isAccessibleRowSelected()" );
560 : }
561 :
562 0 : return FALSE;
563 : }
564 :
565 : /*****************************************************************************/
566 :
567 : static gboolean
568 0 : table_wrapper_is_selected( AtkTable *table,
569 : gint row,
570 : gint column )
571 : {
572 : try {
573 0 : accessibility::XAccessibleTable* pTable = getTable( table );
574 :
575 : #ifdef ENABLE_TRACING
576 : if( pTable )
577 : fprintf(stderr, "isAccessibleSelected( %u, %u ) returns %s\n",
578 : row, column, pTable->isAccessibleSelected( row , column ) ? "true" : "false" );
579 : #endif
580 :
581 0 : if( pTable )
582 0 : return pTable->isAccessibleSelected( row, column );
583 : }
584 0 : catch(const uno::Exception& e) {
585 0 : g_warning( "Exception in isAccessibleSelected()" );
586 : }
587 :
588 0 : return FALSE;
589 : }
590 :
591 : /*****************************************************************************/
592 :
593 : static gboolean
594 0 : table_wrapper_add_row_selection( AtkTable *, gint )
595 : {
596 0 : g_warning( "FIXME: no simple analogue for add_row_selection" );
597 0 : return 0;
598 : }
599 :
600 : /*****************************************************************************/
601 :
602 : static gboolean
603 0 : table_wrapper_remove_row_selection( AtkTable *, gint )
604 : {
605 0 : g_warning( "FIXME: no simple analogue for remove_row_selection" );
606 0 : return 0;
607 : }
608 :
609 : /*****************************************************************************/
610 :
611 : static gboolean
612 0 : table_wrapper_add_column_selection( AtkTable *, gint )
613 : {
614 0 : g_warning( "FIXME: no simple analogue for add_column_selection" );
615 0 : return 0;
616 : }
617 :
618 : /*****************************************************************************/
619 :
620 : static gboolean
621 0 : table_wrapper_remove_column_selection( AtkTable *, gint )
622 : {
623 0 : g_warning( "FIXME: no simple analogue for remove_column_selection" );
624 0 : return 0;
625 : }
626 :
627 : /*****************************************************************************/
628 :
629 : static void
630 0 : table_wrapper_set_caption( AtkTable *, AtkObject * )
631 : { // meaningless helper
632 0 : }
633 :
634 : /*****************************************************************************/
635 :
636 : static void
637 0 : table_wrapper_set_column_description( AtkTable *, gint, const gchar * )
638 : { // meaningless helper
639 0 : }
640 :
641 :
642 : /*****************************************************************************/
643 :
644 : static void
645 0 : table_wrapper_set_column_header( AtkTable *, gint, AtkObject * )
646 : { // meaningless helper
647 0 : }
648 :
649 :
650 : /*****************************************************************************/
651 :
652 : static void
653 0 : table_wrapper_set_row_description( AtkTable *, gint, const gchar * )
654 : { // meaningless helper
655 0 : }
656 :
657 : /*****************************************************************************/
658 :
659 : static void
660 0 : table_wrapper_set_row_header( AtkTable *, gint, AtkObject * )
661 : { // meaningless helper
662 0 : }
663 :
664 : /*****************************************************************************/
665 :
666 : static void
667 0 : table_wrapper_set_summary( AtkTable *, AtkObject * )
668 : { // meaningless helper
669 0 : }
670 :
671 : /*****************************************************************************/
672 :
673 : } // extern "C"
674 :
675 : void
676 0 : tableIfaceInit (AtkTableIface *iface)
677 : {
678 0 : g_return_if_fail (iface != NULL);
679 :
680 0 : iface->ref_at = table_wrapper_ref_at;
681 0 : iface->get_n_rows = table_wrapper_get_n_rows;
682 0 : iface->get_n_columns = table_wrapper_get_n_columns;
683 0 : iface->get_index_at = table_wrapper_get_index_at;
684 0 : iface->get_column_at_index = table_wrapper_get_column_at_index;
685 0 : iface->get_row_at_index = table_wrapper_get_row_at_index;
686 0 : iface->is_row_selected = table_wrapper_is_row_selected;
687 0 : iface->is_selected = table_wrapper_is_selected;
688 0 : iface->get_selected_rows = table_wrapper_get_selected_rows;
689 0 : iface->add_row_selection = table_wrapper_add_row_selection;
690 0 : iface->remove_row_selection = table_wrapper_remove_row_selection;
691 0 : iface->add_column_selection = table_wrapper_add_column_selection;
692 0 : iface->remove_column_selection = table_wrapper_remove_column_selection;
693 0 : iface->get_selected_columns = table_wrapper_get_selected_columns;
694 0 : iface->is_column_selected = table_wrapper_is_column_selected;
695 0 : iface->get_column_extent_at = table_wrapper_get_column_extent_at;
696 0 : iface->get_row_extent_at = table_wrapper_get_row_extent_at;
697 0 : iface->get_row_header = table_wrapper_get_row_header;
698 0 : iface->set_row_header = table_wrapper_set_row_header;
699 0 : iface->get_column_header = table_wrapper_get_column_header;
700 0 : iface->set_column_header = table_wrapper_set_column_header;
701 0 : iface->get_caption = table_wrapper_get_caption;
702 0 : iface->set_caption = table_wrapper_set_caption;
703 0 : iface->get_summary = table_wrapper_get_summary;
704 0 : iface->set_summary = table_wrapper_set_summary;
705 0 : iface->get_row_description = table_wrapper_get_row_description;
706 0 : iface->set_row_description = table_wrapper_set_row_description;
707 0 : iface->get_column_description = table_wrapper_get_column_description;
708 0 : iface->set_column_description = table_wrapper_set_column_description;
709 : }
710 :
711 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|