File size: 5,920 Bytes
4ad5bf3
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
"""
Hyperlink management tools for PowerPoint MCP Server.
Implements hyperlink operations for text shapes and runs.
"""

from typing import Dict, List, Optional, Any

def register_hyperlink_tools(app, presentations, get_current_presentation_id, validate_parameters, 
                          is_positive, is_non_negative, is_in_range, is_valid_rgb):
    """Register hyperlink management tools with the FastMCP app."""
    
    @app.tool()
    def manage_hyperlinks(
        operation: str,
        slide_index: int,
        shape_index: int = None,
        text: str = None, 
        url: str = None,
        run_index: int = 0,
        presentation_id: str = None
    ) -> Dict:
        """
        Manage hyperlinks in text shapes and runs.
        
        Args:
            operation: Operation type ("add", "remove", "list", "update")
            slide_index: Index of the slide (0-based)
            shape_index: Index of the shape on the slide (0-based)
            text: Text to make into hyperlink (for "add" operation)
            url: URL for the hyperlink
            run_index: Index of text run within the shape (0-based)
            presentation_id: Optional presentation ID (uses current if not provided)
            
        Returns:
            Dictionary with operation results
        """
        try:
            # Get presentation
            pres_id = presentation_id or get_current_presentation_id()
            if pres_id not in presentations:
                return {"error": "Presentation not found"}
            
            pres = presentations[pres_id]
            
            # Validate slide index
            if not (0 <= slide_index < len(pres.slides)):
                return {"error": f"Slide index {slide_index} out of range"}
            
            slide = pres.slides[slide_index]
            
            if operation == "list":
                # List all hyperlinks in the slide
                hyperlinks = []
                for shape_idx, shape in enumerate(slide.shapes):
                    if hasattr(shape, 'text_frame') and shape.text_frame:
                        for para_idx, paragraph in enumerate(shape.text_frame.paragraphs):
                            for run_idx, run in enumerate(paragraph.runs):
                                if run.hyperlink.address:
                                    hyperlinks.append({
                                        "shape_index": shape_idx,
                                        "paragraph_index": para_idx,
                                        "run_index": run_idx,
                                        "text": run.text,
                                        "url": run.hyperlink.address
                                    })
                
                return {
                    "message": f"Found {len(hyperlinks)} hyperlinks on slide {slide_index}",
                    "hyperlinks": hyperlinks
                }
            
            # For other operations, validate shape index
            if shape_index is None or not (0 <= shape_index < len(slide.shapes)):
                return {"error": f"Shape index {shape_index} out of range"}
            
            shape = slide.shapes[shape_index]
            
            # Check if shape has text
            if not hasattr(shape, 'text_frame') or not shape.text_frame:
                return {"error": "Shape does not contain text"}
            
            if operation == "add":
                if not text or not url:
                    return {"error": "Both 'text' and 'url' are required for adding hyperlinks"}
                
                # Add new text run with hyperlink
                paragraph = shape.text_frame.paragraphs[0]
                run = paragraph.add_run()
                run.text = text
                run.hyperlink.address = url
                
                return {
                    "message": f"Added hyperlink '{text}' -> '{url}' to shape {shape_index}",
                    "text": text,
                    "url": url
                }
            
            elif operation == "update":
                if not url:
                    return {"error": "URL is required for updating hyperlinks"}
                
                # Update existing hyperlink
                paragraphs = shape.text_frame.paragraphs
                if run_index < len(paragraphs[0].runs):
                    run = paragraphs[0].runs[run_index]
                    old_url = run.hyperlink.address
                    run.hyperlink.address = url
                    
                    return {
                        "message": f"Updated hyperlink from '{old_url}' to '{url}'",
                        "old_url": old_url,
                        "new_url": url,
                        "text": run.text
                    }
                else:
                    return {"error": f"Run index {run_index} out of range"}
            
            elif operation == "remove":
                # Remove hyperlink from specific run
                paragraphs = shape.text_frame.paragraphs
                if run_index < len(paragraphs[0].runs):
                    run = paragraphs[0].runs[run_index]
                    old_url = run.hyperlink.address
                    run.hyperlink.address = None
                    
                    return {
                        "message": f"Removed hyperlink '{old_url}' from text '{run.text}'",
                        "removed_url": old_url,
                        "text": run.text
                    }
                else:
                    return {"error": f"Run index {run_index} out of range"}
            
            else:
                return {"error": f"Unsupported operation: {operation}. Use 'add', 'remove', 'list', or 'update'"}
                
        except Exception as e:
            return {"error": f"Failed to manage hyperlinks: {str(e)}"}